正在加载,请稍候…

GraphQL Federation:跨微服务的统一模式

使用 Apollo Federation v2 实现 GraphQL Federation,学习子图、实体解析、指令、模式组合以及构建分布式 GraphQL 架

GraphQL Federation:跨微服务的统一模式

GraphQL Federation:跨微服务的统一模式

什么是 Federation?

无 Federation:
  Client -> 每个服务有自己的 GraphQL 端点
  Client -> /api/users/graphql
  Client -> /api/orders/graphql
  Client -> /api/products/graphql

使用 Federation:
  Client -> 单一网关 -> 路由到相应的子图
  统一模式:user 有 orders 有 products

GraphQL Federation:跨微服务的统一模式 插图

子图设置

// users-service/schema.ts
import { buildSubgraphSchema } from '@apollo/subgraph';
import { gql } from 'graphql-tag';

const typeDefs = gql`
  extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key", "@shareable"])

  type User @key(fields: "id") {
    id: ID!
    email: String!
    name: String!
    profile: UserProfile
  }

  type UserProfile {
    bio: String
    avatarUrl: String
  }

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

const resolvers = {
  Query: {
    me: (_, __, { userId }) => userRepo.findById(userId),
    user: (_, { id }) => userRepo.findById(id),
  },
  User: {
    // 引用解析器:允许其他子图扩展 User
    __resolveReference(reference: { id: string }) {
      return userRepo.findById(reference.id);
    },
    profile: (user) => userProfileRepo.findByUserId(user.id),
  },
};

export const schema = buildSubgraphSchema({ typeDefs, resolvers });
// orders-service/schema.ts
const typeDefs = gql`
  extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key", "@extends"])

  # 从 users-service 扩展 User 类型
  type User @key(fields: "id") {
    id: ID! @external
    orders(first: Int): OrderConnection!
  }

  type Order @key(fields: "id") {
    id: ID!
    status: OrderStatus!
    total: Float!
    createdAt: String!
    items: [OrderItem!]!
  }

  type Query {
    order(id: ID!): Order
  }
`;

const resolvers = {
  User: {
    orders: (user, { first = 10 }) => orderRepo.findByUserId(user.id, { limit: first }),
  },
  Order: {
    __resolveReference(ref: { id: string }) {
      return orderRepo.findById(ref.id);
    },
  },
};

GraphQL Federation:跨微服务的统一模式 插图

Apollo Router(网关)

# router.yaml
supergraph:
  listen: 0.0.0.0:4000

subgraphs:
  users:
    routing_url: http://users-service:4001/graphql
  orders:
    routing_url: http://orders-service:4002/graphql
  products:
    routing_url: http://products-service:4003/graphql
# 组合超图模式
rover supergraph compose --config supergraph.yaml > supergraph.graphql

# 启动路由器
./router --config router.yaml --supergraph supergraph.graphql

GraphQL Federation:跨微服务的统一模式 插图

模式组合

# 生成的统一模式(由 Apollo Router 自动组合)
type User {
  id: ID!
  email: String!
  name: String!
  profile: UserProfile      # 来自 users-service
  orders(first: Int): OrderConnection!  # 来自 orders-service
  recommendations: [Product!]!  # 来自 products-service
}

客户端查询(跨多个服务)

query GetUserDashboard($userId: ID!) {
  user(id: $userId) {
    name
    email
    # 由 users-service 解析
    profile {
      avatarUrl
    }
    # 由 orders-service 解析
    orders(first: 5) {
      edges {
        node {
          id
          status
          total
        }
      }
    }
  }
}
# Apollo Router 自动:
# 1. 从 users-service 获取用户
# 2. 使用 user.id 从 orders-service 获取订单
# 3. 合并并返回组合结果

模式注册表

# 将子图模式发布到 Apollo Studio
rover subgraph publish my-graph@prod \
  --name users \
  --schema users-service/schema.graphql \
  --routing-url https://users-service.internal/graphql

# 在发布前检查破坏性变更
rover subgraph check my-graph@prod \
  --name users \
  --schema users-service/schema.graphql

Federation 使团队能够独立拥有自己的 GraphQL 模式,同时呈现统一的 API。