12. Referencing an entity
5m

Overview

Let's get back to our problem of how to connect data between . We'll take care of one of the missing pieces of our schema: the Review.location .

In this lesson, we will:

  • Learn how to reference an in a as a return type by implementing the Review.location
The FlyBy schema diagram, with a pencil icon next to the Review.location field

The Location entity as a return type

We want to use the Location as the return type for the Review.location , so let's take a closer look at how to do that.

✏️ Adding the Review.location field to the schema

  1. Open up the subgraph-reviews/reviews.graphql file.

  2. Let's add a new called location, which should return a Location type.

    subgraph-reviews/reviews.graphql
    type Review {
    id: ID!
    "Written text"
    comment: String
    "A number from 1 - 5 with 1 being lowest and 5 being highest"
    rating: Int
    "The location the review is about"
    location: Location
    }
    type Location @key(fields: "id", resolvable: false) {
    id: ID!
    }
  3. We can test our changes and open Sandbox for the reviews at http://localhost:4002. We should see the new location show up under latestReviews.

    studio.apollographql.com/sandbox/explorer
    The Sandbox Explorer page of GraphOS Studio
  4. Let's try running a to test out our new . We'll query for latestReviews, and include the id, comment and rating . Next, we'll include the new location and its id. Let's also give the a descriptive name: GetLatestReviewsAndLocations.

    query GetLatestReviewsAndLocations {
    latestReviews {
    id
    comment
    rating
    location {
    id
    }
    }
    }

When we submit the , we can see that we get back null for the value of each location!

This is because we haven't defined what the reviews should return when this is queried! We first need to define a corresponding function.

✏️ The Review.location resolver function

As we saw before, the will ask the reviews for an representation of the location the review is associated with. The already knows how to retrieve the typename, but it needs the location's id key . Let's set that up.

  1. Open up the subgraph-reviews/resolvers.js file.

  2. In the resolvers object, we'll add a new key for the Review type, and an empty function for the location .

    subgraph-reviews/resolvers.js
    const resolvers = {
    // ...
    Review: {
    location: () => {
    // TODO
    },
    },
    };
  3. Name the first parameter of the function review, which is the parent object of the .

    subgraph-reviews/resolvers.js
    location: (review) => {
    // TODO
    },
  4. For the body of the , we need to return an representation with the location's id. So how do we retrieve the id of a location for a particular review?

    To answer this question, we'll take a quick detour to look at what reviews data we get back from our . Jump over to the reviews_data.json file in the datasources directory. Here we can see that for each review object, we are storing the locationId each review belongs to.

    subgraph-reviews/datasources/reviews_data.json
    {
    "id": "rev-1",
    "locationId": "loc-1",
    "rating": 5,
    "comment": "..."
    }

    This locationId specifies exactly the data we're looking for - a location's id!

  5. Back in the Reviews.location , let's destructure the review object and pull out locationId. Then we'll return a new object that reassigns locationId to id. This will match it to the name of the Location 's @key .

    subgraph-reviews/resolvers.js
    location: ({locationId}) => {
    return {id: locationId};
    },

Checking your work

Fantastic! Now let's check that everything's playing nicely. Go back to for the reviews at http://localhost:4002.

Let's try out that again. This time, we get back each location's id!

query GetLatestReviewsAndLocations {
latestReviews {
id
comment
rating
location {
id
}
}
}

The response should match the shape of the object below:

And now our reviews can resolve a location's id , which is exactly what the will need to associate data across .

To resolve the rest of the Location (like name, description, or photo), we still have one thing left to add to our schema: the Location 's reference resolver!

✏️ Implement the __resolveReference resolver

  1. Moving over to the subgraph-locations directory, open up the resolvers.js file.

  2. Inside the resolvers object, add a new key for Location, then a function called __resolveReference.

    subgraph-locations/resolvers.js
    const resolvers = {
    Query: {
    // ...
    },
    Location: {
    __resolveReference: () => {
    // TODO
    },
    },
    };
  3. Next, let's set up this function's .

    Destructure the first , which is the representation object, and pull out the id from it.

    Similarly, destructure the second (context) to access the dataSources property.

    subgraph-locations/resolvers.js
    __resolveReference: ({id}, {dataSources}) => {
    // TODO
    },
  4. The body of the reference function needs to return all the that this defines. To do this, we'll use the LocationsAPI and its getLocation method. It returns a Location object for a given ID.

    subgraph-locations/resolvers.js
    __resolveReference: ({id}, {dataSources}) => {
    return dataSources.locationsAPI.getLocation(id);
    },

    Note: You can check out how the getLocation method works by peeking inside the subgraph-locations/datasources/LocationsApi.js file.

And with that, our is now fully set up to handle referencing entities!

Okay, we should be ready to our supergraph in Studio, and watch the magic of the associating data between our !

Let's get to building the GetLatestReviews we agreed upon earlier with the frontend team. We'll add our ... wait a minute, where did our location go? Wasn't this working great locally on Sandbox? What happened?

We forgot to publish our reviews changes to the registry!

✏️ Publish subgraph change with Rover

Oops! Let's hop over to a terminal in the root of the project, and run rover subgraph publish, passing in the for the reviews .

rover subgraph publish <APOLLO_GRAPH_REF> \
--name reviews \
--schema ./subgraph-reviews/reviews.graphql

Now we should be ready to query our supergraph in Studio, and watch the magic of the router associating data between our subgraphs!

✏️ Check your work against the router

Let's run this in Studio.

query GetLatestReviews {
latestReviews {
id
comment
rating
location {
name
}
}
}

Note: If you see red squiggly lines below the location on latestReviews, try refreshing the page. You may have been faster than the !

And we can see all our data is coming back from both the locations and reviews !

We should see a response like this:

Let's update our schema agreement checklist and check off the location we just added to the Review type.

The FlyBy schema diagram, with pencil icons next to the Location.reviews and Location.overallRating fields

Practice

When a subgraph references an entity as a return value, it provides a representation of that entity for the router to use. Which of the following are included in that representation?
Which of the below is NOT one of the parameters accepted by the __resolveReference function?

Key takeaways

  • We can reference an in one as the return value for a type's .
  • Any that contributes to an needs to define a __resolveReference function for that . This resolver is called when the needs to resolve references to that entity made from within other .

Up next

Awesome work. Our aren't so isolated anymore. And we're almost done checking off the in our schema agreement. In the next lesson, we'll contribute the last two fields: reviewsForLocation and overallRating.

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.