ไทย

ปลดล็อกศักยภาพของ GraphQL เฟเดอเรชันด้วยการเชื่อมสกีมา (Schema Stitching) เรียนรู้วิธีสร้าง GraphQL API แบบรวมศูนย์จากหลายเซอร์วิส เพื่อเพิ่มความสามารถในการขยายระบบและการบำรุงรักษา

GraphQL เฟเดอเรชัน: การเชื่อมสกีมา (Schema Stitching) - คู่มือฉบับสมบูรณ์

ในโลกของการพัฒนาแอปพลิเคชันสมัยใหม่ที่เปลี่ยนแปลงอยู่ตลอดเวลา ความต้องการสถาปัตยกรรมที่สามารถขยายขนาดและบำรุงรักษาได้กลายเป็นสิ่งสำคัญยิ่ง ไมโครเซอร์วิสซึ่งมีความเป็นโมดูลและการปรับใช้ที่เป็นอิสระต่อกันได้กลายเป็นโซลูชันที่ได้รับความนิยม อย่างไรก็ตาม การจัดการไมโครเซอร์วิสจำนวนมากอาจก่อให้เกิดความซับซ้อน โดยเฉพาะอย่างยิ่งเมื่อต้องเปิดเผย API แบบรวมศูนย์ไปยังแอปพลิเคชันฝั่งไคลเอ็นต์ นี่คือจุดที่ GraphQL เฟเดอเรชัน และโดยเฉพาะอย่างยิ่ง การเชื่อมสกีมา (Schema Stitching) เข้ามามีบทบาท

GraphQL เฟเดอเรชัน คืออะไร?

GraphQL เฟเดอเรชัน คือสถาปัตยกรรมที่ทรงพลังที่ช่วยให้คุณสามารถสร้าง GraphQL API แบบรวมศูนย์เพียงหนึ่งเดียวจากบริการ GraphQL หลายๆ ตัวที่อยู่เบื้องหลัง (ซึ่งมักจะเป็นตัวแทนของไมโครเซอร์วิส) ช่วยให้นักพัฒนาสามารถสืบค้นข้อมูลข้ามบริการต่างๆ ได้ราวกับว่าเป็นกราฟเดียว ทำให้ประสบการณ์ฝั่งไคลเอ็นต์ง่ายขึ้นและลดความจำเป็นในการใช้ตรรกะการประสานงานที่ซับซ้อนฝั่งไคลเอ็นต์

มีแนวทางหลักสองประการสำหรับ GraphQL เฟเดอเรชัน:

บทความนี้จะเน้นไปที่ การเชื่อมสกีมา (Schema Stitching) โดยจะสำรวจแนวคิด ประโยชน์ ข้อจำกัด และการนำไปใช้งานจริง

ทำความเข้าใจเกี่ยวกับการเชื่อมสกีมา (Schema Stitching)

การเชื่อมสกีมา (Schema Stitching) คือกระบวนการรวมสกีมา GraphQL หลายๆ ตัวเข้าด้วยกันเป็นสกีมาเดียวที่เชื่อมโยงกัน สกีมาที่รวมศูนย์นี้ทำหน้าที่เป็นส่วนหน้า (facade) เพื่อซ่อนความซับซ้อนของบริการเบื้องหลังจากไคลเอ็นต์ เมื่อไคลเอ็นต์ส่งคำขอไปยังสกีมาที่เชื่อมกัน เกตเวย์จะกำหนดเส้นทางคำขอไปยังบริการที่เหมาะสมอย่างชาญฉลาด ดึงข้อมูล และรวมผลลัพธ์ก่อนส่งกลับไปยังไคลเอ็นต์

ลองนึกภาพตามนี้: คุณมีร้านอาหารหลายแห่ง (บริการ) ที่แต่ละแห่งเชี่ยวชาญด้านอาหารที่แตกต่างกัน การเชื่อมสกีมาเปรียบเสมือนเมนูสากลที่รวบรวมอาหารทั้งหมดจากแต่ละร้านอาหาร เมื่อลูกค้า (ไคลเอ็นต์) สั่งอาหารจากเมนูสากล คำสั่งซื้อจะถูกส่งไปยังห้องครัวของร้านอาหารที่เหมาะสมอย่างชาญฉลาด อาหารจะถูกเตรียมและรวมกันเป็นการจัดส่งเดียวสำหรับลูกค้า

แนวคิดหลักในการเชื่อมสกีมา

ประโยชน์ของการเชื่อมสกีมา

การเชื่อมสกีมามีประโยชน์ที่น่าสนใจหลายประการสำหรับองค์กรที่ใช้สถาปัตยกรรมไมโครเซอร์วิส:

ข้อจำกัดของการเชื่อมสกีมา

แม้ว่าการเชื่อมสกีมาจะมีข้อดีมากมาย แต่สิ่งสำคัญคือต้องตระหนักถึงข้อจำกัดของมัน:

การนำไปใช้งานจริงของการเชื่อมสกีมา

ลองดูตัวอย่างอย่างง่ายเกี่ยวกับวิธีการนำ Schema Stitching ไปใช้โดยใช้ Node.js และไลบรารี graphql-tools (ซึ่งเป็นตัวเลือกยอดนิยมสำหรับการเชื่อมสกีมา) ตัวอย่างนี้เกี่ยวข้องกับไมโครเซอร์วิสสองตัว: User Service และ Product Service

1. กำหนดสกีมาระยะไกล

ขั้นแรก ให้กำหนดสกีมา GraphQL สำหรับแต่ละบริการระยะไกล

User Service (user-service.js):


const { buildSchema } = require('graphql');

const userSchema = buildSchema(`
  type User {
    id: ID!
    name: String
    email: String
  }

  type Query {
    user(id: ID!): User
  }
`);

const users = [
  { id: '1', name: 'Alice Smith', email: 'alice@example.com' },
  { id: '2', name: 'Bob Johnson', email: 'bob@example.com' },
];

const userRoot = {
  user: (args) => users.find(user => user.id === args.id),
};

module.exports = {
  schema: userSchema,
  rootValue: userRoot,
};

Product Service (product-service.js):


const { buildSchema } = require('graphql');

const productSchema = buildSchema(`
  type Product {
    id: ID!
    name: String
    price: Float
    userId: ID!  # Foreign key to User Service
  }

  type Query {
    product(id: ID!): Product
  }
`);

const products = [
  { id: '101', name: 'Laptop', price: 1200, userId: '1' },
  { id: '102', name: 'Smartphone', price: 800, userId: '2' },
];

const productRoot = {
  product: (args) => products.find(product => product.id === args.id),
};

module.exports = {
  schema: productSchema,
  rootValue: productRoot,
};

2. สร้างบริการเกตเวย์

ตอนนี้ ให้สร้างบริการเกตเวย์ที่จะเชื่อมสกีมาทั้งสองเข้าด้วยกัน

Gateway Service (gateway.js):


const { stitchSchemas } = require('@graphql-tools/stitch');
const { makeRemoteExecutableSchema } = require('@graphql-tools/wrap');
const { graphqlHTTP } = require('express-graphql');
const express = require('express');
const { introspectSchema } = require('@graphql-tools/wrap');
const { printSchema } = require('graphql');
const fetch = require('node-fetch');

async function createRemoteSchema(uri) {
  const fetcher = async (params) => {
    const response = await fetch(uri, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(params),
    });
    return response.json();
  };

  const schema = await introspectSchema(fetcher);
  return makeRemoteExecutableSchema({
    schema,
    fetcher,
  });
}

async function main() {
  const userSchema = await createRemoteSchema('http://localhost:4001/graphql');
  const productSchema = await createRemoteSchema('http://localhost:4002/graphql');

  const stitchedSchema = stitchSchemas({
    subschemas: [
      { schema: userSchema },
      { schema: productSchema },
    ],
    typeDefs: `
      extend type Product {
        user: User
      }
    `,
    resolvers: {
      Product: {
        user: {
          selectionSet: `{ userId }`,
          resolve(product, args, context, info) {
            return info.mergeInfo.delegateToSchema({
              schema: userSchema,
              operation: 'query',
              fieldName: 'user',
              args: {
                id: product.userId,
              },
              context,
              info,
            });
          },
        },
      },
    },
  });

  const app = express();
  app.use('/graphql', graphqlHTTP({
    schema: stitchedSchema,
    graphiql: true,
  }));

  app.listen(4000, () => console.log('Gateway server running on http://localhost:4000/graphql'));
}

main().catch(console.error);

3. รันเซอร์วิส

คุณจะต้องรัน User Service และ Product Service บนพอร์ตที่แตกต่างกัน ตัวอย่างเช่น:

User Service (พอร์ต 4001):


const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./user-service');

const app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: rootValue,
  graphiql: true,
}));

app.listen(4001, () => console.log('User service running on http://localhost:4001/graphql'));

Product Service (พอร์ต 4002):


const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./product-service');

const app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: rootValue,
  graphiql: true,
}));

app.listen(4002, () => console.log('Product service running on http://localhost:4002/graphql'));

4. สืบค้นสกีมาที่เชื่อมกัน

ตอนนี้คุณสามารถสืบค้นสกีมาที่เชื่อมกันผ่านเกตเวย์ (ที่รันบนพอร์ต 4000) คุณสามารถรันการสืบค้นเช่นนี้:


query {
  product(id: "101") {
    id
    name
    price
    user {
      id
      name
      email
    }
  }
}

การสืบค้นนี้จะดึงข้อมูลผลิตภัณฑ์ที่มี ID "101" และยังดึงข้อมูลผู้ใช้ที่เกี่ยวข้องจาก User Service ซึ่งแสดงให้เห็นว่าการเชื่อมสกีมาช่วยให้คุณสามารถสืบค้นข้อมูลข้ามบริการหลายตัวได้ในคำขอเดียว

เทคนิคการเชื่อมสกีมาขั้นสูง

นอกเหนือจากตัวอย่างพื้นฐานแล้ว นี่คือเทคนิคขั้นสูงบางอย่างที่สามารถใช้เพื่อปรับปรุงการใช้งาน Schema Stitching ของคุณ:

การเลือกระหว่าง Schema Stitching และ Apollo Federation

ในขณะที่ Schema Stitching เป็นตัวเลือกที่ใช้ได้สำหรับ GraphQL Federation แต่ Apollo Federation ได้กลายเป็นตัวเลือกที่ได้รับความนิยมมากกว่าเนื่องจากคุณสมบัติขั้นสูงและประสบการณ์ของนักพัฒนาที่ดีกว่า นี่คือการเปรียบเทียบของทั้งสองแนวทาง:

ฟีเจอร์ Schema Stitching Apollo Federation
การกำหนดสกีมา ใช้ภาษา GraphQL schema ที่มีอยู่ ใช้ภาษาสกีมาแบบประกาศพร้อมไดเร็กทีฟ
การวางแผนการสืบค้น ต้องการการมอบหมายการสืบค้นด้วยตนเอง การวางแผนการสืบค้นอัตโนมัติโดย Apollo Gateway
การขยายประเภท การสนับสนุนที่จำกัด การสนับสนุนในตัวสำหรับการขยายประเภท
ไดเร็กทีฟคีย์ ไม่รองรับ ใช้ไดเร็กทีฟ @key เพื่อระบุเอนทิตี
การติดตามแบบกระจาย ต้องการการใช้งานด้วยตนเอง การสนับสนุนในตัวสำหรับการติดตามแบบกระจาย
เครื่องมือและระบบนิเวศ เครื่องมือที่ยังไม่สมบูรณ์เท่า เครื่องมือที่สมบูรณ์กว่าและมีชุมชนขนาดใหญ่
ความซับซ้อน อาจซับซ้อนในการจัดการในระบบขนาดใหญ่ ออกแบบมาสำหรับระบบขนาดใหญ่และซับซ้อน

ควรเลือก Schema Stitching เมื่อไหร่:

ควรเลือก Apollo Federation เมื่อไหร่:

ตัวอย่างและกรณีการใช้งานในโลกแห่งความเป็นจริง

นี่คือตัวอย่างในโลกแห่งความเป็นจริงว่า GraphQL Federation รวมถึง Schema Stitching สามารถนำไปใช้ได้อย่างไร:

แนวทางปฏิบัติที่ดีที่สุดสำหรับ Schema Stitching

เพื่อให้แน่ใจว่าการใช้งาน Schema Stitching ประสบความสำเร็จ ให้ปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดเหล่านี้:

สรุป

GraphQL Federation ด้วย Schema Stitching เป็นแนวทางที่ทรงพลังในการสร้าง API แบบรวมศูนย์จากหลายบริการในสถาปัตยกรรมไมโครเซอร์วิส โดยการทำความเข้าใจแนวคิดหลัก, ประโยชน์, ข้อจำกัด และเทคนิคการใช้งาน คุณสามารถใช้ประโยชน์จาก Schema Stitching เพื่อทำให้การเข้าถึงข้อมูลง่ายขึ้น, ปรับปรุงความสามารถในการขยายขนาด และเพิ่มประสิทธิภาพการบำรุงรักษา ในขณะที่ Apollo Federation ได้กลายเป็นโซลูชันขั้นสูงกว่า แต่ Schema Stitching ยังคงเป็นตัวเลือกที่ใช้ได้สำหรับสถานการณ์ที่เรียบง่ายกว่าหรือเมื่อรวมบริการ GraphQL ที่มีอยู่แล้ว ควรพิจารณาความต้องการและข้อกำหนดเฉพาะของคุณอย่างรอบคอบเพื่อเลือกแนวทางที่ดีที่สุดสำหรับองค์กรของคุณ

GraphQL เฟเดอเรชัน: การเชื่อมสกีมา (Schema Stitching) - คู่มือฉบับสมบูรณ์ | MLOG