From harness-claude
Composes unified GraphQL APIs from independently deployed subgraphs using Apollo Federation for multi-team domains, large schema splitting, and cross-service type extensions.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Compose a unified GraphQL API from independently deployed subgraph services using Apollo Federation
Guides authoring Apollo Federation 2 subgraph schemas for supergraphs, including @key entities, @shareable types/fields, directives (@external, @requires, @provides, @override, @inaccessible), design patterns, and composition error troubleshooting.
Designs GraphQL schemas with Apollo Federation directives, implements resolvers using DataLoader, builds real-time subscriptions, and optimizes for security and performance.
Designs GraphQL schemas with Apollo Federation directives, implements resolvers using DataLoader, real-time subscriptions, and optimizes queries for performance and security.
Share bugs, ideas, or general feedback.
Compose a unified GraphQL API from independently deployed subgraph services using Apollo Federation
orders to User from the orders service)User, the orders service defines Order. No type is defined in two places — types are extended across boundaries.# users subgraph
type User @key(fields: "id") {
id: ID!
name: String!
email: String!
}
type Query {
user(id: ID!): User
}
Use @key to mark entity types. An entity is a type that can be referenced and extended by other subgraphs. The @key directive specifies which fields uniquely identify the entity.
Extend entities in other subgraphs with stub types. The orders service references User without redefining it — it provides only the key field and adds new fields.
# orders subgraph
type User @key(fields: "id") {
id: ID!
orders: [Order!]!
}
type Order @key(fields: "id") {
id: ID!
total: Money!
status: OrderStatus!
customer: User!
}
__resolveReference for each entity. This resolver is called by the gateway when it needs to hydrate a stub entity. It receives the key fields and returns the full object.const resolvers = {
User: {
__resolveReference: (ref: { id: string }, { dataSources }) => {
return dataSources.users.findById(ref.id);
},
},
};
# supergraph-config.yaml
subgraphs:
users:
routing_url: http://users-service:4001/graphql
schema:
subgraph_url: http://users-service:4001/graphql
orders:
routing_url: http://orders-service:4002/graphql
schema:
subgraph_url: http://orders-service:4002/graphql
Use @shareable for fields that multiple subgraphs can resolve. In Federation v2, fields are exclusive by default. Mark fields @shareable when multiple subgraphs need to return the same field.
Use @override to migrate fields between subgraphs. When moving a field from one subgraph to another, the new owner uses @override(from: "old-subgraph") to claim resolution without a breaking change.
Use @external, @provides, and @requires for computed fields. @requires tells the gateway to fetch specified fields from the owning subgraph before calling the current resolver.
# shipping subgraph
type Order @key(fields: "id") {
id: ID!
weight: Float @external
shippingCost: Float @requires(fields: "weight")
}
Run composition checks in CI. Use rover subgraph check to validate that schema changes in one subgraph do not break the composed supergraph before deploying.
Keep the gateway stateless. The router/gateway should not contain business logic — it composes and routes. All business logic lives in subgraphs.
Federation v1 vs. v2: Federation v2 (current) uses @link to import federation directives, supports @shareable, @override, @inaccessible, and progressive @override for safe migrations. Prefer v2 for new projects.
Query planning: The gateway decomposes incoming queries into subgraph fetches. A query for user { name orders { total } } fetches name from the users subgraph, then fetches orders from the orders subgraph using the user's id as the reference key. This happens transparently.
Performance considerations:
__resolveReference on the owning subgraph@provides to return extra fields alongside entities to reduce follow-up fetches__resolveReference using DataLoaderOwnership rules:
@key fields must be resolvable by the defining subgraph@shareable)@key) must be identical across subgraphsCommon mistakes:
__resolveReference — the gateway cannot hydrate the entity@key fields without updating all referencing subgraphshttps://www.apollographql.com/docs/federation/