9. Connecting data using entities
7m

Overview

The foundation of our is complete. We've separated FlyBy's into location data and review data, and we've implemented subgraphs that only define the types they're concerned with.

Revisiting our agreement checklist, we still have three s that we don't know how to implement yet:

  • Location.reviewsForLocation and Location.overallRating: These are both fields of the Location type, but we decided we want them to be owned by the reviews subgraph.
  • Review.location: This is a field on the Review type (which lives in the reviews subgraph), but the field has a return type of Location, which is defined in the locations subgraph.
The FlyBy schema diagram, with the three remaining fields in focus

To implement these s, we need to add a new tool to our developer tool belts: entities!

In this lesson, we will:

  • Learn what an entity is and what it's used for
  • Learn how to define an entity
  • Learn how the router represents entities when it talks between subgraphs

What's an entity?

An entity is an with s split between multiple subgraphs.

This means we can define a type that both of our subgraphs can contribute s to and resolve independently.

Illustration of 2 subgraphs contributing fieleds to an entity.

In FlyBy, we want our reviews to include the location that they are written about. Our Location type needs to be used by both subgraphs, so we'll be turning the Location type into an entity.

A subgraph that defines an entity can do one or both of the following:

  1. Reference the entity
  2. Contribute fields to the entity

Reference the entity

Referencing an entity means using it as a return type for another defined in the subgraph.

For example, in the reviews subgraph, we can add a location to the Review type, which will reference the Location entity as its return type.

The Review type, with a location field that has a return value of a Location type

Contribute fields to the entity

Contributing s to an entity means that one subgraph adds new s to an entity that are specific to that subgraph's concerns.

For example, the Location entity will have s for name, description, and photo, which will live in the locations subgraph. In other words, the locations subgraph contributes these s to the Location entity.

And the reviews subgraph contributes two review-specific s to the Location entity: reviewsForLocation and overallRating.

The Location entity, with fields divided between the locations and reviews subgraph

How to create an entity

To convert an object into an entity in the subgraph , we need to do two things:

  1. Define a primary key
  2. Define a reference resolver

Defining a primary key

An entity's primary key is the (or s) that can uniquely identify an instance of that entity within a subgraph. The uses primary keys to collect data from across multiple subgraphs and associate it with a single entity instance.

For example, a location entity's primary key is its id. The uses that id to collect data about a specific location instance, like a location with id "loc-1".

Illustration showing three entities with unique ids

In each of our subgraph s, we can define a primary key for an entity, by adding the @key after the type's name.

The @key needs a property called fields, which we'll set to the we want to use as the entity's primary key.

Entity syntax
type EntityType @key(fields: "id")
Illustration showing the syntax for defining an entity. See code snippet above for an example.

Defining a reference resolver function

Each subgraph that contributes s to an entity also needs to define a special function for that entity called a reference resolver. The uses reference s to directly access the entity s that each subgraph contributes.

Illustration of each subgraph contributing fields to an entity with an associated reference resolver.

Every reference has the name: __resolveReference. We define each entity's reference right alongside all the s for that type.

The __resolveReference function has a slightly different signature from other functions. Instead of the usual four s, __resolveReference only takes three:

  • reference: The entity representation object that's passed in by the router. This tells the subgraph which instance of an entity is being requested. We'll cover what an entity representation is in the section below.
  • context: The object shared across all resolvers. (This is the same as in normal resolvers, but note that by convention, we refer to this __resolveReference argument as context, rather than contextValue as in other resolvers!)
  • info: Contains information about the operation's execution state, just like in a normal resolver. We won't use this argument much.
Illustration of each subgraph contributing fields to an entity with an associated reference resolver.

Let's focus on this first , reference, and learn more about entity representations.

What's an entity representation?

An entity representation is an object that the uses to represent a specific instance of an entity. A representation always includes the typename for that entity and the @key for the specific instance.

  • The __typename field: This field exists on all GraphQL types automatically. It always returns the name of its containing type, as a string. For example, Location.__typename returns "Location".
  • The @key field: The key-value pair that a subgraph can use to identify the instance of an entity. For example, if we defined the Location entity using the "id" field as a primary key, then our entity representation would include an "id" property with a value like "loc-2".

An entity representation for a location might look like this:

Example location entity representation
{
"__typename": "Location",
"id": "loc-2"
}

You can think of an entity representation as a passport that the uses to refer to a particular object between subgraphs.

The typename is like a passport's country of origin. It says which entity the object belongs to. And the @key is like a passport's ID number, uniquely identifying this instance of that entity.

The representation object is like a passport

Practice

Where should an entity's __resolveReference function be defined?
Check your understanding!
An entity's primary key is used to identify a unique instance of that entity within a 
 
. To define a primary key, apply the 
 
 directive and pass in the name of the primary key field as the value of the 
 
 property. An entity can have 
 
 primary key.

Drag items from this box to the blanks above

  • @unique

  • reference resolver

  • @key

  • keys

  • fields

  • router

  • more than one

  • subgraph

  • @primary

  • only one

Key takeaways

  • An entity is a type that can resolve its fields across multiple subgraphs.
  • To create an entity, we can use the @key directive to specify which field(s) can uniquely identify an object of that type.
  • We can use entities in two ways:
    • As a return type for a field (referencing an entity).
    • Defining fields for an entity from multiple subgraphs (contributing to an entity).
  • Any subgraph that contributes fields to an entity needs to define a reference resolver function for that entity. This __resolveReference resolver is called whenever the router needs to access fields of the entity from within another subgraph.
  • An entity representation is an object that the router uses to represent a specific instance of an entity. It includes the entity's type and its key field(s).

Up next

We've covered a lot about entities! In the next lesson, we'll jump back into the code for our subgraphs and define our first entity.

Previous
Next