واجهات GraphQL

النشر والإنتاج

20 دقيقة الدرس 31 من 35

النشر والإنتاج

يتطلب نشر واجهة برمجة تطبيقات GraphQL إلى بيئة الإنتاج تخطيطًا دقيقًا وتكوينًا لضمان الأمان والأداء والموثوقية. يغطي هذا الدرس استراتيجيات النشر وأفضل ممارسات الإنتاج وخيارات الاستضافة السحابية.

تكوين بيئة الإنتاج

قبل النشر، قم بتكوين تطبيقك للإنتاج:

// .env.production NODE_ENV=production PORT=4000 DATABASE_URL=postgresql://user:password@host:5432/dbname REDIS_URL=redis://host:6379 JWT_SECRET=your-production-secret-here CORS_ORIGIN=https://yourdomain.com RATE_LIMIT_MAX=100 INTROSPECTION_ENABLED=false PLAYGROUND_ENABLED=false
تنبيه أمني: لا تقم أبدًا بحفظ أسرار الإنتاج في نظام التحكم بالإصدارات. استخدم متغيرات البيئة أو خدمات إدارة الأسرار مثل AWS Secrets Manager أو HashiCorp Vault.

نشر Apollo Server على استضافة Node.js

النشر على منصات استضافة Node.js التقليدية:

// server.js - تكوين الإنتاج const { ApolloServer } = require('apollo-server-express'); const express = require('express'); const helmet = require('helmet'); const compression = require('compression'); const app = express(); // وسيط الأمان app.use(helmet({ contentSecurityPolicy: process.env.NODE_ENV === 'production', crossOriginEmbedderPolicy: false, })); // وسيط الضغط app.use(compression()); // نقطة نهاية فحص الصحة app.get('/health', (req, res) => { res.status(200).json({ status: 'ok', timestamp: new Date() }); }); const server = new ApolloServer({ typeDefs, resolvers, context: ({ req }) => ({ user: req.user, dataSources: { db: pool, cache: redisClient, }, }), introspection: process.env.INTROSPECTION_ENABLED === 'true', playground: process.env.PLAYGROUND_ENABLED === 'true', plugins: [ // مراقبة الإنتاج ApolloServerPluginLandingPageDisabled(), ApolloServerPluginInlineTrace(), ], formatError: (error) => { // إخفاء تفاصيل الأخطاء الداخلية في الإنتاج if (process.env.NODE_ENV === 'production') { console.error(error); return new Error('Internal server error'); } return error; }, }); await server.start(); server.applyMiddleware({ app, path: '/graphql' }); const PORT = process.env.PORT || 4000; app.listen(PORT, () => { console.log(`🚀 Server ready at http://localhost:${PORT}${server.graphqlPath}`); });

GraphQL بدون خادم مع AWS Lambda

نشر GraphQL كدالة بدون خادم:

// lambda.js const { ApolloServer } = require('apollo-server-lambda'); const typeDefs = require('./schema'); const resolvers = require('./resolvers'); const server = new ApolloServer({ typeDefs, resolvers, context: ({ event, context }) => ({ headers: event.headers, functionName: context.functionName, event, context, }), introspection: false, playground: false, }); exports.handler = server.createHandler({ cors: { origin: 'https://yourdomain.com', credentials: true, }, });
# serverless.yml service: graphql-api provider: name: aws runtime: nodejs18.x region: us-east-1 environment: DATABASE_URL: ${env:DATABASE_URL} JWT_SECRET: ${env:JWT_SECRET} functions: graphql: handler: lambda.handler events: - http: path: graphql method: post cors: true - http: path: graphql method: get cors: true
فوائد Serverless: ادفع فقط مقابل ما تستخدمه، توسع تلقائي، صيانة خادم صفرية. مثالي لواجهات برمجة التطبيقات ذات أنماط حركة المرور المتغيرة.

النشر باستخدام Docker

احتواء واجهة برمجة تطبيقات GraphQL باستخدام Docker:

# Dockerfile FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . FROM node:18-alpine WORKDIR /app COPY --from=builder /app . ENV NODE_ENV=production EXPOSE 4000 USER node CMD ["node", "server.js"]
# docker-compose.yml version: '3.8' services: graphql-api: build: . ports: - "4000:4000" environment: - DATABASE_URL=postgresql://postgres:password@db:5432/mydb - REDIS_URL=redis://redis:6379 depends_on: - db - redis db: image: postgres:15-alpine environment: POSTGRES_DB: mydb POSTGRES_PASSWORD: password volumes: - postgres_data:/var/lib/postgresql/data redis: image: redis:7-alpine volumes: - redis_data:/data volumes: postgres_data: redis_data:

استراتيجية CDN والتخزين المؤقت

تطبيق رؤوس التخزين المؤقت لطلبات GET:

const express = require('express'); const app = express(); // التحكم في التخزين المؤقت لطلبات GraphQL GET app.get('/graphql', (req, res, next) => { if (req.query.query && !req.query.query.includes('mutation')) { // تخزين الاستعلامات للقراءة فقط لمدة 5 دقائق res.set('Cache-Control', 'public, max-age=300'); } else { res.set('Cache-Control', 'no-store'); } next(); }); // استخدام CDN للأصول الثابتة app.use(express.static('public', { maxAge: '1y', etag: true, }));
تكامل CDN: استخدم خدمات مثل CloudFlare أو AWS CloudFront أو Fastly لتخزين استجابات GraphQL مؤقتًا في مواقع الحافة حول العالم، مما يقلل من زمن الوصول للمستخدمين العالميين.

قائمة التحقق من الإنتاج

قائمة التحقق قبل النشر:
  • ✅ تعطيل الاستبطان وساحة اللعب في الإنتاج
  • ✅ تطبيق حدود معدل وحدود تعقيد الاستعلام
  • ✅ إعداد تسجيل ومراقبة الأخطاء (Sentry، LogRocket)
  • ✅ تكوين CORS مع أصول مسموح بها محددة
  • ✅ استخدام HTTPS/TLS لجميع حركة المرور
  • ✅ تطبيق تجميع اتصالات قاعدة البيانات
  • ✅ إعداد نقاط نهاية فحص الصحة
  • ✅ تكوين النسخ الاحتياطية التلقائية لقاعدة البيانات
  • ✅ الاختبار بحجم بيانات مشابه للإنتاج
  • ✅ توثيق واجهة برمجة التطبيقات مع توثيق المخطط
  • ✅ إعداد خط أنابيب CI/CD للنشر التلقائي
  • ✅ تكوين متغيرات البيئة بشكل آمن

المراقبة والملاحظة

// استخدام Apollo Studio للمراقبة const { ApolloServer } = require('apollo-server'); const { ApolloServerPluginUsageReporting } = require('apollo-server-core'); const server = new ApolloServer({ typeDefs, resolvers, plugins: [ ApolloServerPluginUsageReporting({ sendVariableValues: { none: true }, sendHeaders: { none: true }, }), ], }); // مقاييس مخصصة مع Prometheus const prometheus = require('prom-client'); const register = new prometheus.Registry(); const httpRequestDuration = new prometheus.Histogram({ name: 'http_request_duration_seconds', help: 'Duration of HTTP requests in seconds', labelNames: ['method', 'route', 'status_code'], registers: [register], }); app.get('/metrics', async (req, res) => { res.set('Content-Type', register.contentType); res.end(await register.metrics()); });
الأداء: راقب أوقات تنفيذ الاستعلام ومعدلات الأخطاء وموارد الخادم. قم بإعداد تنبيهات للحالات الشاذة لاكتشاف المشكلات قبل أن تؤثر على المستخدمين.

استراتيجيات التوسع

التوسع الأفقي مع موازن التحميل:

# nginx.conf - تكوين موازن التحميل upstream graphql_backend { least_conn; server graphql-server-1:4000; server graphql-server-2:4000; server graphql-server-3:4000; } server { listen 80; server_name api.yourdomain.com; location /graphql { proxy_pass http://graphql_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } }
التوسع التلقائي: استخدم Kubernetes أو مجموعات التوسع التلقائي السحابية لإضافة/إزالة مثيلات الخادم تلقائيًا بناءً على أنماط حركة المرور. قم بتعيين عتبات CPU والذاكرة لمحفزات التوسع.