Join us from October 8-10 in New York City to learn the latest tips, trends, and news about GraphQL Federation and API platform engineering.Join us for GraphQL Summit 2024 in NYC
Docs
Start for Free

Contribute and Reference Entity Fields

Contribute and reference entity fields across subgraphs


In a federated architecture, individual can contribute to and reference from shared entities. This guide explains how subgraphs work together to build a cohesive schema, with examples of contributing and computing fields, as well as referencing entities without contributing fields.

Contributing entity fields

Any number of different subgraphs can contribute fields to an entity definition. In the example below, the Products and Inventory subgraphs contribute different fields to the Product entity:

Products subgraph
type Product @key(fields: "id") {
id: ID!
name: String!
price: Int
}
Inventory subgraph
type Product @key(fields: "id") {
id: ID!
inStock: Boolean!
}

By default, each must contribute different fields, with the important exception of @key fields. If multiple subgraphs attempt to contribute the same field, a error occurs. To override this default behavior, see Resolving another subgraph's field.

Each subgraph that contributes fields to an entity must define a reference resolver for that entity.

Contributing computed entity fields

You can define entity fields that are computed from values of other entity fields, even when a different subgraph resolves those fields.

For example, this Shipping subgraph adds a shippingEstimate to the Product entity. This field is calculated based on the product's size and weight, which the Products subgraph defines:

Shipping subgraph
type Product @key(fields: "id") {
id: ID!
size: Int @external
weight: Int @external
shippingEstimate: String @requires(fields: "size weight")
}
Products subgraph
type Product @key(fields: "id") {
id: ID!
name: String!
price: Int
size: Int
weight: Int
}

Notice the Shipping subgraph uses two :

  • The @requires indicates which fields are required from other subgraphs.
  • The @external directives is applied to required fields in the type definition.
    • This directive tells the , "This subgraph knows these fields exist, but it can't resolve them itself."

How the router processes computed entity fields

In the previous example, if a requests a product's shippingEstimate, the router does the following:

  1. It queries the Products subgraph for the product's size and weight.
  2. It queries the Shipping subgraph for the product's shippingEstimate.
  • It includes the size and weight of the Product object passed to the for shippingEstimate:

    resolvers.js
    {
    Product: {
    shippingEstimate(product) {
    return computeShippingEstimate(product.id, product.size, product.weight);
    }
    }
    }

Using @requires with object subfields

If a computed field @requires a field that returns an , you also specify which subfields of that object are required. You list those subfields with the following syntax:

Shipping subgraph
type Product @key(fields: "id") {
id: ID!
dimensions: ProductDimensions @external
shippingEstimate: String @requires(fields: "dimensions { size weight }")
}

In this modification of the previous example, size and weight are now subfields of a ProductDimensions object. The Products and Shipping subgraphs must both define the ProductDimensions type for this to be valid.

Using @requires with fields that take arguments
Since 2.1.2

Starting in Federation v2.1.2, the @requires directive can include fields that take , like so:

Shipping subgraph
type Product @key(fields: "id") {
id: ID!
weight(units: String): Int @external
shippingEstimate: String @requires(fields: "weight(units:\"KILOGRAMS\")")
}

The following rules apply:

  • The router provides the specified values in its query to whichever subgraph defines the required field.
  • Each specified value is static; the router always provides the same value.
  • You can omit values for nullable arguments. You must provide values for non-nullable arguments.
  • If you define your in an file instead of programmatically, you must escape quotes for string and enum values with backslashes (as shown above).

Referencing an entity without contributing fields

Your subgraphs can use an entity as a field's return type without contributing any fields to that entity.

For example, take a look at this Product entity in the Products subgraph:

Products subgraph
type Product @key(fields: "id") {
id: ID!
name: String!
price: Int
}

Suppose you want to create a Reviews subgraph that includes the following Review type:

Reviews subgraph
type Review {
product: Product!
score: Int!
}

While this is possible, the current Reviews subgraph schema is invalid because it doesn't define the Product entity.

To fix this, add a stub of the Product entity to the Reviews schema, like so:

Reviews subgraph
type Review {
product: Product!
score: Int!
}
type Product @key(fields: "id", resolvable: false) {
id: ID!
}

A stub definition includes only the @key fields of an entity. In this case, the Product type definition only includes the id field. It also includes resolvable: false in the @key directive to indicate that this subgraph doesn't define a reference resolver for the Product entity.

Previous
Define Advanced Keys
Next
Resolve Another Subgraph's Fields
Rate articleRateEdit on GitHubEditForumsDiscord

© 2024 Apollo Graph Inc., d/b/a Apollo GraphQL.

Privacy Policy

Company