The GraphQL Composite Schemas spec refers to downstream GraphQL APIs that have been designed for composition as subgraphs. These subgraphs may have additional directives specified in this section to indicate semantics of type system members in the overall graph.
Subgraph directives offer instructions for the schema composition process, detailing type system member semantics and specifying type transformations. In some cases subgraph schemas can be composed without any directives.
directive @entityResolver on FIELD_DEFINITION
Entity resolvers are fields on the query root type of a subgraph that can resolve an entity by a stable key. The stable key is defined by the arguments of the field.
extend type Query {
version: Int # NOT an entity resolver.
personById(id: ID!): Person @entityResolver
}
extend type Person {
id: ID! # matches the argument of personById
}
The arguments of an entity resolver field must match fields of the returning type.
extend type Query {
node(id: ID!): Node @entityResolver
}
interface Node {
id: ID!
}
When an entity resolver returns an interface all implementing types are inferred as entities.
extend type Query {
entityById(id: ID!, categoryId: Int): Entity @entityResolver
}
union Entity = Cat | Dog
extend type Dog {
id: ID!
categoryId: Int
}
extend type Cat {
id: ID!
categoryId: Int
}
directive @is(
field: FieldSelection
coordinate: Schemacoordinate
) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
The @is
directive is utilized to establish semantic equivalence between
disparate type system members across distinct subgraphs, which the schema
composition uses to connect types.
In the following example, the directive specifies that the id
argument on the
field Query.personById
and the field Person.id
on the return type of the
field are semantically the same. This information is used to infer an entity
resolver for Person
from the field Query.personById
.
extend type Query {
personById(id: ID! @is(field: "id")): Person @entityResolver
}
The @is
directive also allows to refer to nested fields relative to Person
.
extend type Query {
personByAddressId(id: ID! @is(field: "address { id }")): Person
}
The @is
directive not limited to a single argument.
extend type Query {
personByAddressId(
id: ID! @is(field: "address { id }")
kind: PersonKind @is(field: "kind")
): Person
}
The directive can also establish semantic equivalence between two output fields.
In this example, the field productSKU
is semantically equivalent to the field
Product.sku
, allowing the schema composition to infer the connection of the
Product
with the Review
type.
extend type Review {
productSKU: ID! @is(coordinate: "Product.sku") @internal
product: Product @resolve
}
The @is
directive can use either the field
or coordinate
argument. If both
are specified, the schema composition must fail.
extend type Review {
productSKU: ID!
@is(coordinate: "Product.sku", field: "product { sku }")
@internal
product: Product @resolve
}
Arguments:
field
: Represents a GraphQL field selection syntax that refers to field relative to the current type; or, when used on arguments it refers to a field relative to the return type.coordinate
: Represents a schema coordinate that refers to a type system member.
directive @shareable repeatable on OBJECT | FIELD_DEFINITION
By default, only one subgraph is allowed to contribute a particular field to an object type. This prevents subgraphs from inadvertently defining similarly named fields that are semantically not the same.
Fields have to be explicitly marked as @shareable
to allow multiple subgraphs
to define it. And it ensures the step of allowing a field to be served from
multiple subgraphs is an explicit, coordinated decision.
If multiple subgraphs define the same field, these are assumed to be semantically equivalent, and the executor is free to choose between them as it sees fit.
Note: Key fields are always considered sharable.
directive @require(
field: FieldSelection!
) on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
The @require
directive is used to express data requirements with other
subgraphs. Arguments annotated with the @require
directive are removed from
the public exposed schema and the value for these will be resolved by the
executor.
type Product {
id: ID!
delivery(
zip: String!
size: Int! @require(field: "dimension { size }")
weight: Int! @require(field: "dimension { weight }")
): DeliveryEstimates
}
This can also be done by using input types. All fields of the input type that match the required output type are required. If the input type is only used to express a requirement it is removed from the public schema.
type Product {
id: ID!
delivery(
zip: String!
dimension: ProductDimensionInput! @require(field: "dimension"))
): DeliveryEstimates
}
directive @provides(fields: SelectionSet!) on FIELD_DEFINITION
The @provides
directive is an optimization hint specifying child fields that
can be resolved locally at the given subgraph through a particular query path.
This allows for a variation of overlapping field to improve data fetching.
directive @external on OBJECT_DEFINITION | INTERFACE_DEFINITION | FIELD_DEFINITION
The @external
directive is used in combination with the @provides
directive
and specifies data that is not owned ba a particular subgraph.
directive @override(from: String!) on FIELD_DEFINITION
The @override
directive allows to migrate fields from one subgraph to another.
directive @internal on OBJECT | INTERFACE | FIELD_DEFINITION | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCALAR
The @internal
directive signals to the composition process that annotated type
system members shall not be included into the public schema but still can be
used by the executor to build resolvers.
scalar Schemacoordinate
The Schemacoordinate
scalar represents a schema coordinate syntax.
Product.id
Product.estimateDelivery(zip:)