9. Connecting data using entities
7m

Overview

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

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

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

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

In this lesson, we will:

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

What's an entity?

An entity is an with split between multiple .

This means we can define a type that both of our can contribute 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 , so we'll be turning the Location type into an .

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

  1. Reference the
  2. Contribute to the

Reference the entity

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

For example, in the reviews , we can add a location to the Review type, which will reference the Location 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 to an means that one adds new fields to an entity that are specific to that subgraph's concerns.

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

And the reviews contributes two review-specific to the Location : 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 in the , we need to do two things:

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

Defining a primary key

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

For example, a location '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 , we can define a primary key for an , 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 's primary key.

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

Defining a reference resolver function

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

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

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

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

  • reference: The representation object that's passed in by the . This tells the 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 . (This is the same as in normal resolvers, but note that by convention, we refer to this __resolveReference as context, rather than contextValue as in other !)
  • info: Contains information about the 's execution state, just like in a normal . We won't use this 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 representations.

What's an entity representation?

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

  • The __typename field: This exists on all 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 can use to identify the instance of an . For example, if we defined the Location using the "id" as a primary key, then our entity representation would include an "id" property with a value like "loc-2".

An representation for a location might look like this:

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

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

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

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

  • subgraph

  • @primary

  • more than one

  • keys

  • @unique

  • reference resolver

  • only one

  • @key

  • fields

  • router

Key takeaways

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

Up next

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

Previous

Share your questions and comments about this lesson

Your feedback helps us improve! If you're stuck or confused, let us know and we'll help you out. All comments are public and must follow the Apollo Code of Conduct. Note that comments that have been resolved or addressed may be removed.

You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.