واجهات GraphQL
دمج المخططات والاتحاد
دمج المخططات والاتحاد
تعلم كيفية دمج مخططات GraphQL متعددة في واجهة برمجة تطبيقات موحدة باستخدام دمج المخططات واتحاد Apollo.
مفهوم دمج المخططات
يتيح لك دمج المخططات دمج مخططات GraphQL متعددة في مخطط موحد واحد:
const { stitchSchemas } = require('@graphql-tools/stitch');
const { makeExecutableSchema } = require('@graphql-tools/schema');
// مخطط خدمة المستخدمين
const userSchema = makeExecutableSchema({
typeDefs: `
type User {
id: ID!
name: String!
email: String!
}
type Query {
user(id: ID!): User
users: [User!]!
}
`,
resolvers: {
Query: {
user: (_, { id }) => getUserById(id),
users: () => getAllUsers(),
},
},
});
// مخطط خدمة المنتجات
const productSchema = makeExecutableSchema({
typeDefs: `
type Product {
id: ID!
name: String!
price: Float!
}
type Query {
product(id: ID!): Product
products: [Product!]!
}
`,
resolvers: {
Query: {
product: (_, { id }) => getProductById(id),
products: () => getAllProducts(),
},
},
});
// دمج المخططات معاً
const stitchedSchema = stitchSchemas({
subschemas: [userSchema, productSchema],
});
اتحاد Apollo
اتحاد Apollo هو نهج أكثر تطوراً لبنية GraphQL الموزعة:
// مخطط فرعي للمستخدمين (users-service)
const { ApolloServer, gql } = require('apollo-server');
const { buildSubgraphSchema } = require('@apollo/subgraph');
const typeDefs = gql`
type User @key(fields: "id") {
id: ID!
name: String!
email: String!
}
extend type Query {
user(id: ID!): User
users: [User!]!
}
`;
const resolvers = {
Query: {
user: (_, { id }) => getUserById(id),
users: () => getAllUsers(),
},
User: {
__resolveReference(user) {
return getUserById(user.id);
},
},
};
const server = new ApolloServer({
schema: buildSubgraphSchema({ typeDefs, resolvers }),
port: 4001,
});
server.listen().then(({ url }) => {
console.log(`خدمة المستخدمين جاهزة على ${url}`);
});
المخططات الفرعية والمخطط الفائق
حدد علاقات الكيانات عبر المخططات الفرعية:
// مخطط فرعي للطلبات (orders-service)
const typeDefs = gql`
type Order @key(fields: "id") {
id: ID!
userId: ID!
user: User!
items: [OrderItem!]!
total: Float!
status: OrderStatus!
}
type OrderItem {
productId: ID!
product: Product!
quantity: Int!
price: Float!
}
enum OrderStatus {
PENDING
PROCESSING
SHIPPED
DELIVERED
CANCELLED
}
# توسيع User من users-service
extend type User @key(fields: "id") {
id: ID! @external
orders: [Order!]!
}
# توسيع Product من products-service
extend type Product @key(fields: "id") {
id: ID! @external
}
extend type Query {
order(id: ID!): Order
orders: [Order!]!
}
`;
const resolvers = {
Query: {
order: (_, { id }) => getOrderById(id),
orders: () => getAllOrders(),
},
Order: {
__resolveReference(order) {
return getOrderById(order.id);
},
user(order) {
return { __typename: 'User', id: order.userId };
},
},
User: {
orders(user) {
return getOrdersByUserId(user.id);
},
},
OrderItem: {
product(item) {
return { __typename: 'Product', id: item.productId };
},
},
};
ملاحظة: يحدد التوجيه
@key المفتاح الأساسي للكيان. يشير التوجيه @external إلى الحقول المعرفة في مخطط فرعي آخر.
محللات الكيانات
نفذ محللات المراجع لجلب الكيانات عبر الخدمات:
// مخطط فرعي للمنتجات مع محلل الكيان
const typeDefs = gql`
type Product @key(fields: "id") {
id: ID!
name: String!
description: String!
price: Float!
stock: Int!
}
extend type Query {
product(id: ID!): Product
products: [Product!]!
}
`;
const resolvers = {
Query: {
product: (_, { id }) => getProductById(id),
products: () => getAllProducts(),
},
Product: {
// يتم استدعاء هذا المحلل عندما تطلب خدمة أخرى هذا الكيان
__resolveReference(reference) {
return getProductById(reference.id);
},
},
};
إعداد البوابة
قم بتكوين بوابة Apollo لدمج جميع المخططات الفرعية:
const { ApolloServer } = require('apollo-server');
const { ApolloGateway, IntrospectAndCompose } = require('@apollo/gateway');
// حدد نقاط نهاية المخططات الفرعية
const gateway = new ApolloGateway({
supergraphSdl: new IntrospectAndCompose({
subgraphs: [
{ name: 'users', url: 'http://localhost:4001/graphql' },
{ name: 'products', url: 'http://localhost:4002/graphql' },
{ name: 'orders', url: 'http://localhost:4003/graphql' },
],
}),
});
const server = new ApolloServer({
gateway,
subscriptions: false,
});
server.listen({ port: 4000 }).then(({ url }) => {
console.log(`البوابة جاهزة على ${url}`);
});
نصيحة: استخدم الاتحاد المُدار مع Apollo Studio لتركيب المخطط التلقائي والتحقق في بيئات الإنتاج.
ملف تكوين المخطط الفائق
حدد بنية الاتحاد الخاصة بك بشكل تصريحي:
# supergraph-config.yaml
federation_version: 2
subgraphs:
users:
routing_url: http://users-service:4001/graphql
schema:
file: ./users-schema.graphql
products:
routing_url: http://products-service:4002/graphql
schema:
file: ./products-schema.graphql
orders:
routing_url: http://orders-service:4003/graphql
schema:
file: ./orders-schema.graphql
# إنشاء مخطط فائق
rover supergraph compose --config supergraph-config.yaml > supergraph.graphql
# بدء البوابة بالمخطط المُرَكَّب
const { readFileSync } = require('fs');
const gateway = new ApolloGateway({
supergraphSdl: readFileSync('./supergraph.graphql').toString(),
});
تحذير: يمكن أن تسبب التبعيات الدائرية بين المخططات الفرعية مشاكل في الحل. صمم علاقات الكيان الخاصة بك بعناية لتجنب الحلقات اللانهائية.
اختبار استعلامات الاتحاد
استعلم عبر مخططات فرعية متعددة بسلاسة:
query GetUserWithOrders {
user(id: "1") {
id
name
email
orders {
id
total
status
items {
quantity
price
product {
id
name
price
}
}
}
}
}
تمرين:
- أنشئ ثلاثة مخططات فرعية (users, products, orders) باستخدام اتحاد Apollo
- حدد علاقات الكيانات باستخدام التوجيهات
@keyوextend - نفذ محللات المراجع للاستعلامات عبر الخدمات
- قم بإعداد بوابة Apollo لدمج جميع المخططات الفرعية
- اختبر استعلاماً يمتد عبر خدمات متعددة