Subchapter 3.2
references/directives.mdMarkdown19 KBView on GitHub
directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACEDesignates an object type as an entity with a unique key for cross-subgraph resolution.
| Option | Type | Default | Description |
|---|---|---|---|
fields | String! | — | Selection set of key fields |
resolvable | Boolean | true | Whether this subgraph can resolve the entity |
type Product @key(fields: "id") {
id: ID!
name: String!
}Use multiple fields when a single field isn’t unique:
type User @key(fields: "username domain") {
username: String!
domain: String!
}type User @key(fields: "id organization { id }") {
id: ID!
organization: Organization!
}
type Organization {
id: ID!
}Use resolvable: false to reference entities without contributing fields:
type Product @key(fields: "id", resolvable: false) {
id: ID!
}Define multiple keys if there are multiple ways to uniquely identify an entity:
type Product @key(fields: "id") @key(fields: "sku") {
id: ID!
sku: String!
name: String!
}Subgraphs can use different keys, but must share at least one:
# Products subgraph
type Product @key(fields: "sku") @key(fields: "upc") {
sku: ID!
upc: String!
name: String!
}
# Inventory subgraph
type Product @key(fields: "upc") {
upc: String!
inStock: Boolean!
}Allows a subgraph to add fields to all implementations of an entity interface without knowing the individual types. Requires Federation 2.3+.
directive @interfaceObject on OBJECT@key(s) as the interface@interfaceObject subgraphs cannot define individual implementations# Subgraph A - defines entity interface
interface Media @key(fields: "id") {
id: ID!
title: String!
}
type Book implements Media @key(fields: "id") {
id: ID!
title: String!
author: String!
}
# Subgraph B - adds fields to all implementations
type Media @key(fields: "id") @interfaceObject {
id: ID!
reviews: [Review!]!
}Composition adds reviews to Media interface and all implementations.
directive @shareable repeatable on FIELD_DEFINITION | OBJECTAllows multiple subgraphs to resolve the same field.
@shareable in any subgraph, must be @shareable or @external in alltype Product @key(fields: "id") {
id: ID!
name: String! @shareable
price: Int
}If applied on a type definition, all of that type’s fields are considered @shareable.
type Position @shareable {
x: Int!
y: Int!
}@shareable only applies to fields in the same declaration:
type Position @shareable {
x: Int! # shareable
y: Int! # shareable
}
extend type Position {
z: Int! # NOT shareable - needs explicit @shareable
}directive @inaccessible on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITIONHides a field or type from the public API schema while keeping it available internally for query planning.
Safely add shared fields across subgraphs in stages. Mark the field @inaccessible until all subgraphs define it, then remove the directive.
type Position @shareable {
x: Int!
y: Int!
z: Int! @inaccessible # hidden from API schema
}Use private data as @key and/or @requires data without exposing it to clients.
# subgraph A
type Product @key(fields: "id") {
id: ID!
secret: String! @inaccessible
}
# subgraph B
type Product @key(fields: "id") {
id: ID!
secret: String! @external
computed: String @requires(fields: "secret")
}directive @override(from: String!) on FIELD_DEFINITIONMigrates a field from one subgraph to another.
| Option | Type | Default | Description |
|---|---|---|---|
from | String! | — | Name of the subgraph to override |
label | String | — | Progressive override label (Enterprise). Requires Federation 2.7+ |
@external fields@provides or @requiresfrom must match subgraph name exactlyStart resolving amount from this subgraph instead of Payments.
type Bill @key(fields: "id") {
id: ID!
amount: Int! @override(from: "Payments")
}Gradually migrate traffic using percentages:
# Start with 1%
amount: Int! @override(from: "Payments", label: "percent(1)")
# Increase to 50%
amount: Int! @override(from: "Payments", label: "percent(50)")
# Complete migration
amount: Int! @override(from: "Payments", label: "percent(100)")directive @authenticated on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUMIndicates that the target element is accessible only to the authenticated supergraph users. Requires Federation 2.5+.
directive @requiresScopes(scopes: [[federation__Scope!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUMIndicates that the target element is accessible only to the authenticated supergraph users with the appropriate JWT scopes. Requires Federation 2.5+.
| Option | Type | Default | Description |
|---|---|---|---|
scopes | [[federation__Scope!]!]! | — | List of JWT scopes required to access the underlying data |
User query requires read:user JWT scope
type Query {
user(id: ID!): User @requiresScopes(scopes: [["read:user"]])
}User query requires read:user AND read:pii JWT scope.
type Query {
user(id: ID!): User @requiresScopes(scopes: [["read:user", "read:pii"]])
}User query requires read:user OR admin JWT scope.
type Query {
user(id: ID!): User @requiresScopes(scopes: [["read:user"], ["admin"]])
}User query requires either both read:user AND read:pii OR admin JWT scope.
type Query {
user(id: ID!): User @requiresScopes(scopes: [["read:user", "read:pii"], ["admin"]])
}directive @policy(policies: [[federation__Policy!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUMIndicates that access to the target element is restricted based on authorization policies that will be evaludated by the router. Requires Federation 2.6+.
| Option | Type | Default | Description |
|---|---|---|---|
policies | [[federation__Policy!]!]! | — | List of authorization policies to evaluate |
User query requires reader policy
type Query {
user(id: ID!): User @policy(policies: [["reader"]])
}User query requires reader AND personal_data policies.
type Query {
user(id: ID!): User @policy(policies: [["reader", "personal_data"]])
}User query requires reader OR admin policies.
type Query {
user(id: ID!): User @policy(policies: [["reader"], ["admin"]])
}User query requires either both reader AND personal_data OR admin policies.
type Query {
user(id: ID!): User @policy(policies: [["reader", "personal_data"], ["admin"]])
}directive @external on FIELD_DEFINITION | OBJECTMarks a field as resolved by another subgraph. Used with @requires, @provides, and entity stubs.
@requires — declare fields needed for computation@provides — declare fields this subgraph can conditionally resolveresolvable: false — not needed on entity stubs (key fields only)directive @provides(fields: FieldSet!) on FIELD_DEFINITIONDeclares that a field can resolve an @external field at a specific query path.
| Option | Type | Default | Description |
|---|---|---|---|
fields | String! | — | Selection set of optionally resolved local fields |
@external@shareable or @external in all subgraphs defining it@shareable in at least one other subgraphSubgraph can resolve Product.name locally only for outOfStockProducts query
type Product @key(fields: "id") {
id: ID!
name: String! @external
}
type Query {
outOfStockProducts: [Product!]! @provides(fields: "name")
discontinuedProducts: [Product!]! # cannot resolve name here
}directive @requires(fields: FieldSet!) on FIELD_DEFINITIONDefines computed fields that depend on values from other subgraphs.
| Option | Type | Default | Description |
|---|---|---|---|
fields | String! | — | Selection set of required fields |
The router fetches size and weight from the owning subgraph first, then calls this subgraph with those values available.
type Product @key(fields: "id") {
id: ID!
size: Int @external
weight: Int @external
shippingEstimate: String @requires(fields: "size weight")
}directive @tag(name: String!) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMAApplies arbitrary metadata to a schema location. Custom tooling can use this metadata during any step of the schema delivery flow, including composition, static analysis, and documentation. Used by GraphOS Enterprise contracts feature.
| Option | Type | Default | Description |
|---|---|---|---|
name | String! | — | Tag name to apply |
directive @composeDirective(name: String!) repeatable on SCHEMAPreserves a specific custom type system directive usage defined in a subgraph schema in the supergraph schema. Requires Federation 2.3+
| Option | Type | Default | Description |
|---|---|---|---|
name | String! | — | Custom directive name to preserve |
@link directive@link specextend schema
@link(url: "https://specs.apollo.dev/link/v1.0")
@link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@composeDirective"])
@link(url: "https://myspecs.dev/myDirective/v1.0", import: ["@myDirective"])
@composeDirective(name: "@myDirective")
directive @myDirective(a: String!) on FIELD_DEFINITION
type Query {
helloWorld: String @myDirective
}directive @context(name: String!) repeatable on OBJECT | INTERFACE | UNIONDefines a named context from which a field of the annotated type can be passed
to a receiver of the context. The receiver must be a field annotated with the
@fromContext directive. Requires Federation 2.8+.
| Option | Type | Default | Description |
|---|---|---|---|
name | String! | — | Context name |
@context directives@context name can be applied in multiple places within a subgraphdirective @fromContext(field: ContextFieldValue) on ARGUMENT_DEFINITIONSets the context from which to receive the value of the annotated field. The
context must have been defined with the @context directive. Requires Federation 2.8+.
| Option | Type | Default | Description |
|---|---|---|---|
field | ContextFieldValue! | — | Field selection set from target context |
@fromContext can only be applied on nullable argumentsContextFieldValue selection must be the name of a context defined by @context and prefixed with $@context name has to be accessible through one of the ancestor selection pathsContextFieldValue selection must be a selection set that resolves to a single fieldContextFieldValue selection can specify type conditions but they cannot overlapContextFieldValue selection must be defined within the current subgraphContextFieldValue selection are resolved across subgraphs, they must be annotated with @externalContextFieldValue selection cannot specify any directivestype Query {
a: A
}
type A @key(fields: "id") @context(name: "userContext") {
id: ID!
prop: String!
u: U
}
type U @key(fields: "id") {
id: ID!
field (arg: String @fromContext(field: "$userContext { prop }")): String!
}type Query {
a: A!
b: B!
}
type A @key(fields: "id") @context(name: "context1"){
id: ID!
field: String!
child: Child!
}
type B @key(fields: "id") @context(name: "context1"){
id: ID!
otherField: String!
child: Child!
}
type Child @key(fields: "id") {
id: ID!
prop(
arg: String!
@fromContext(field: "$context1 ... on A { field } ... on B { otherField } ")
): Int!
}type Query {
a: A
}
type A @key(fields: "id") @context(name: "userContext") {
id: ID!
# this field is resolved by other subgraph
prop: String! @external
u: U
}
type U @key(fields: "id") {
id: ID!
field (arg: String @fromContext(field: "$userContext { prop }")): String!
}directive @cost(weight: Int!) on ARGUMENT_DEFINITION | ENUM | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | OBJECT | SCALARDefine custom weight for resolving a schema location. Requires Federation 2.9+.
| Option | Type | Default | Description |
|---|---|---|---|
weight | Int! | — | Custom weight for scoring current field |
directive @listSize(assumedSize: Int, slicingArguments: [String!], sizedFields: [String!], requireOneSlicingArgument: Boolean = true) on FIELD_DEFINITIONProvide weight estimates for list fields that can be used for calculating query cost. Requires Federation 2.9+.
| Option | Type | Default | Description |
|---|---|---|---|
assumedSize | Int | — | Estimated list size |
slicingArguments | [String!] | - | |
requireOneSlicingArgument | Boolean | true |
Assume items query will return 10 items and use that for query cost estimation.
type Query {
items: [Item!] @listSize(assumedSize: 10)
}Use pagination arguments to specify maximum list size to be equal to the specified last count
type Query {
items(first: Int): [Item!] @listSize(slicingArguments: ["first"])
}directive @cacheTag(format: String!) repeatable on FIELD_DEFINITION | OBJECTAssign cache tag to the cached data. Requires Federation 2.12+.
| Option | Type | Default | Description |
|---|---|---|---|
format | String! | — | String template that defines cache tag |
@cacheTag can only be applied on root query fields and entity types@cacheTag format can be a static string or use interpolated variables@cacheTag is applied on a root field, use {$args.name} to interpolate field arguments@cacheTag is applied on an entity, use {$key.fieldName} to interpolate entity key fieldsAssign tags to the queries
type Query {
# static tag
users: [User!]! @cacheTag(format: "users-list")
# tag with variables
user(id: ID!): User @cacheTag(format: "user-{$args.id}")
}Assign custom tag that includes id to a User entity
type User @key(fields: "id") @cacheTag(format: "user-{$key.id}") {
id: ID!
name: String!
}This file