| name | graphql-federation |
| description | GraphQL Federation skill for creating correct federation subgraphs. Use when: (1) Creating new federation subgraphs, (2) Adding entities with @key directives, (3) Extending types across subgraphs, (4) Using federation directives (@shareable, @external, @override, @provides, @requires, @inaccessible, @interfaceObject, @authenticated, @requiresScopes), (5) Debugging composition errors, (6) Understanding federation rules and patterns.
MANDATORY TRIGGERS: federation, subgraph, @key, entity, federated graph, supergraph, GraphQL composition, router schema
|
GraphQL Federation Skill
Create correct GraphQL federation subgraphs following WunderGraph Cosmo composition rules.
Core Concepts
Subgraph: A GraphQL microservice contributing to the federated graph.
Federated Graph/Supergraph: The composed GraphQL interface for clients.
Router: Plans operations, routes requests to subgraphs, joins data.
Entity: A type with @key directive resolvable across subgraphs.
Router Schema vs Client Schema: Router sees all fields; clients don't see @inaccessible items.
Essential Directives
@key - Define Entities
type User @key(fields: "id") {
id: ID!
name: String!
}
type Product @key(fields: "id") @key(fields: "sku") {
id: ID!
sku: String!
name: String!
}
type Review @key(fields: "author { id } product { id }") {
author: User!
product: Product!
rating: Int!
}
type User @key(fields: "id", resolvable: false) {
id: ID!
}
Key Rules:
- Key fields cannot have arguments
- Key fields cannot be abstract types (interfaces/unions)
- Key fields must select leaf scalars or nested objects with selections
- Multiple keys provide alternative resolution paths
@shareable - Allow Multiple Definitions
type User @key(fields: "id") {
id: ID!
name: String! @shareable
}
type User @key(fields: "id") @shareable {
id: ID!
name: String!
email: String!
}
Shareable Rules:
- Fields defined in multiple subgraphs MUST be @shareable
- Key fields used in other subgraphs' keys must be @shareable
- Root type fields (Query, Mutation) are implicitly shareable
@external - Reference External Fields
extend type User @key(fields: "id") {
id: ID! @external
name: String! @external
reviews: [Review!]!
}
External Rules:
- Use on key fields when extending entities
- Use on fields referenced in @requires
- Use on fields referenced in @provides
- External fields are NOT resolved by this subgraph
@requires - Depend on External Data
type Product @key(fields: "id") {
id: ID!
price: Float! @external
currency: String! @external
formattedPrice: String! @requires(fields: "price currency")
}
Requires Rules:
- Referenced fields must be @external
- Can reference nested fields:
@requires(fields: "details { weight }")
- Router fetches required fields before calling this resolver
@provides - Declare Additional Fields
type Query {
topProducts: [Product!]! @provides(fields: "name description")
}
type Product @key(fields: "id") {
id: ID!
name: String! @external
description: String! @external
}
Provides Rules:
- Declares that a resolver provides additional fields
- Referenced fields must be @external in this subgraph
- Optimizes router query planning
@override - Transfer Field Ownership
type User @key(fields: "id") {
id: ID!
name: String! @override(from: "old-service")
}
Override Rules:
- Cannot override from same subgraph
- Overridden field in source doesn't need @shareable
- Used for gradual migration between subgraphs
@inaccessible - Hide from Client Schema
type User @key(fields: "id") {
id: ID!
name: String!
internalId: String! @inaccessible
}
type InternalMetrics @inaccessible {
requestCount: Int!
}
Inaccessible Rules:
- Field exists in router schema but not client schema
- Still subject to @shareable rules
- All fields on a type cannot be @inaccessible (type becomes useless)
- Required arguments cannot be @inaccessible alone
@interfaceObject - Treat Interface as Object
interface Media @key(fields: "id") {
id: ID!
title: String!
}
type Book implements Media @key(fields: "id") {
id: ID!
title: String!
author: String!
}
type Media @key(fields: "id") @interfaceObject {
id: ID!
reviews: [Review!]!
}
InterfaceObject Rules:
- Cannot define implementations alongside @interfaceObject
- Fields propagate to all concrete implementations
- Must have @key matching the interface's key
Authorization Directives
type Query {
publicData: String!
privateData: String! @authenticated
adminData: String! @requiresScopes(scopes: [["admin"], ["superuser"]])
}
type SecretDocument @authenticated @requiresScopes(scopes: [["read:secrets"]]) {
content: String!
}
Common Patterns
Entity Extension
type User @key(fields: "id") {
id: ID!
name: String!
email: String!
}
extend type User @key(fields: "id") {
id: ID! @external
posts: [Post!]!
}
type Post @key(fields: "id") {
id: ID!
title: String!
author: User!
}
Federated Mutations
type Mutation {
createUser(input: CreateUserInput!): User!
}
type User @key(fields: "id") {
id: ID!
name: String!
}
Interface Entities
interface Node @key(fields: "id") {
id: ID!
}
type User implements Node @key(fields: "id") {
id: ID!
name: String!
}
type Product implements Node @key(fields: "id") {
id: ID!
title: String!
}
Error Prevention
Shareability Errors
type User @key(fields: "id") {
id: ID!
name: String!
}
type User @key(fields: "id") {
id: ID!
name: String!
}
type User @key(fields: "id") {
id: ID!
name: String! @shareable
}
Resolvability Errors
type Query {
user: User!
}
type User {
id: ID!
name: String!
}
type User {
email: String!
}
type User @key(fields: "id") {
id: ID!
name: String!
}
External Field Errors
type Product @key(fields: "id") {
id: ID!
price: Float!
formattedPrice: String! @requires(fields: "price")
}
type Product @key(fields: "id") {
id: ID!
price: Float! @external
formattedPrice: String! @requires(fields: "price")
}
Reference Files
For detailed directive specifications, see:
references/directives.md - Complete directive documentation
references/composition-rules.md - Composition validation rules
references/patterns.md - Advanced federation patterns