واجهات GraphQL

دمج المخططات والاتحاد

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

دمج المخططات والاتحاد

تعلم كيفية دمج مخططات 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 } } } } }
تمرين:
  1. أنشئ ثلاثة مخططات فرعية (users, products, orders) باستخدام اتحاد Apollo
  2. حدد علاقات الكيانات باستخدام التوجيهات @key و extend
  3. نفذ محللات المراجع للاستعلامات عبر الخدمات
  4. قم بإعداد بوابة Apollo لدمج جميع المخططات الفرعية
  5. اختبر استعلاماً يمتد عبر خدمات متعددة