واجهات GraphQL
النشر والإنتاج
النشر والإنتاج
يتطلب نشر واجهة برمجة تطبيقات 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 والذاكرة لمحفزات التوسع.