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

Entities in Apollo Federation

Learn how to define federated types across multiple subgraphs


Entities are a fundamental building block of . In a , an is an that can resolve its across multiple . Each subgraph can contribute different fields to the entity and is responsible for resolving only the fields that it contributes. This enables subgraphs to adhere to the separation of concerns principle.

For example, this Product entity's fields are defined and resolved across two subgraphs:

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

NOTE

Only can be entities.

This guide goes over how to define entities in your and code.

Defining an entity

To define an entity within a particular , you do the following:

  1. Apply the @key directive to an object type.
  2. Define the object type's reference resolver.

1. Define a @key

In a , you can designate any object type as an entity by adding the @key to its definition, like so:

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

The @key directive defines an entity's unique key, which consists of one or more of the type's fields. In the previous example, the Product entity's unique key is its id . Every instance of an entity must be uniquely identifiable by its @key field(s). Key fields' uniqueness enable your to associate fields from different subgraphs with the same entity instance.

In most cases, the @key field(s) for the same entity will be the same across subgraphs. For example, if one subgraph uses id as the @key field for the Product entity, other subgraphs should likely do the same. However, this isn't strictly required.

If coming from a database context, it can be helpful to think of a @key as an entity's primary key. This term isn't completely accurate for entities since a single entity can have multiple @keys. The field(s) you select for an entity's @key must, however, uniquely identify the entity. In that way, @keys are similar to candidate keys.

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

For more information on advanced key options, like defining multiple keys or compound keys, see the guide on Defining keys.

Key field limitations

An entity's @key cannot include:

  • that return a union or interface
  • Fields that take s

Though not strictly required, it's best to use non-nullable fields for keys. If you use fields that return null values, may encounter issues resolving the entity.

2. Define a reference resolver

The @key directive effectively tells the router, "This subgraph can resolve an instance of this entity if you provide its unique key." For this to be true, the subgraph must define a reference resolver for the entity.

NOTE

This section describes how to create reference in . If you're using another subgraph-compatible library, see its documentation for creating reference resolvers or the equivalent functionality.

For the Product entity defined above, the reference might look like this:

resolvers.js
// Products subgraph
const resolvers = {
Product: {
__resolveReference(productRepresentation) {
return fetchProductByID(productRepresentation.id);
}
},
// ...other resolvers...
}

Let's break this example down:

  • You declare an entity's reference resolver in your resolver map, as a member of the entity's corresponding object.
  • A reference resolver's name is always __resolveReference.
  • A reference resolver's first parameter is a representation of the entity being resolved.
    • An entity representation is an object that contains the entity's @key fields, plus its __typename field. These values are automatically provided to your subgraph by your router.
  • A reference resolver is responsible for returning all of the entity fields that this subgraph defines.
    • In this example, the hypothetical fetchProductByID function fetches a particular Product's field data based on its id.

NOTE

A particular reference resolver might be called many times to resolve a single . It's crucial that reference resolvers account for "N+1" issues (typically via data loaders). For details, see Handling the N+1 problem.

Every subgraph that contributes at least one unique field to an entity must define a reference resolver for that entity.

To learn more about __resolveReference in Apollo Server, see the API docs.

Next steps

Once you publish your updated subgraph schemas, GraphOS composes them into a . Clients your supergraph can interact with entity fields without needing to know the details of which subgraphs contribute which fields.

To learn about more advanced ways of using entities, check out these guides:

Previous
Composition
Next
Define Advanced Keys
Rate articleRateEdit on GitHubEditForumsDiscord

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

Privacy Policy

Company