Overview
Let's get back to our problem of how to connect data between subgraphs. We'll take care of one of the missing pieces of our schema: the Review.location
field.
In this lesson, we will:
- Learn how to reference an entity in a subgraph as a return type by implementing the
Review.location
field
The Location
entity as a return type
We want to use the Location
entity as the return type for the Review.location
field, so let's take a closer look at how to do that.
✏️ Adding the Review.location
field to the schema
Open up the
subgraph-reviews/reviews.graphql
file.Let's add a new field called
location
, which should return aLocation
type.subgraph-reviews/reviews.graphqltype 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!}We can test our changes and open Sandbox for the
reviews
subgraph at http://localhost:4002. We should see the newlocation
field show up underlatestReviews
.studio.apollographql.com/sandbox/explorerLet's try running a query to test out our new field. We'll query for
latestReviews
, and include theid
,comment
andrating
fields. Next, we'll include the newlocation
field and itsid
. Let's also give the operation a descriptive name:GetLatestReviewsAndLocations
.query GetLatestReviewsAndLocations {latestReviews {idcommentratinglocation {id}}}
When we submit the query, we can see that we get back null
for the value of each location
!
This is because we haven't defined what the reviews
subgraph should return when this field is queried! We first need to define a corresponding resolver function.
✏️ The Review.location
resolver function
As we saw before, the router will ask the reviews
subgraph for an entity representation of the location the review is associated with. The router already knows how to retrieve the typename, but it needs the location's id key field. Let's set that up.
Open up the
subgraph-reviews/resolvers.js
file.In the
resolvers
object, we'll add a new key for theReview
type, and an empty resolver function for thelocation
field.subgraph-reviews/resolvers.jsconst resolvers = {// ...Review: {location: () => {// TODO},},};Name the first parameter of the resolver function
review
, which is theparent
object of the field.subgraph-reviews/resolvers.jslocation: (review) => {// TODO},For the body of the resolver, we need to return an entity 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 data source. Jump over to the
reviews_data.json
file in thedatasources
directory. Here we can see that for each review object, we are storing thelocationId
each review belongs to.subgraph-reviews/datasources/reviews_data.json{"id": "rev-1","locationId": "loc-1","rating": 5,"comment": "..."}This
locationId
field specifies exactly the data we're looking for - a location'sid
!Back in the
Reviews.location
resolver, let's destructure thereview
object and pull outlocationId
. Then we'll return a new object that reassignslocationId
toid
. This will match it to the name of theLocation
entity's@key
field.subgraph-reviews/resolvers.jslocation: ({locationId}) => {return {id: locationId};},
Checking your work
Fantastic! Now let's check that everything's playing nicely. Go back to Apollo Sandbox for the reviews
subgraph at http://localhost:4002.
Let's try out that query again. This time, we get back each location's id!
query GetLatestReviewsAndLocations {latestReviews {idcommentratinglocation {id}}}
The response should match the shape of the object below:
And now our reviews
subgraph can resolve a location's id
field, which is exactly what the router will need to associate data across subgraphs.
To resolve the rest of the Location
fields (like name
, description
, or photo
), we still have one thing left to add to our schema: the Location
entity's reference resolver!
✏️ Implement the __resolveReference
resolver
Moving over to the
subgraph-locations
directory, open up theresolvers.js
file.Inside the
resolvers
object, add a new key forLocation
, then a resolver function called__resolveReference
.subgraph-locations/resolvers.jsconst resolvers = {Query: {// ...},Location: {__resolveReference: () => {// TODO},},};Next, let's set up this function's arguments.
Destructure the first argument, which is the entity representation object, and pull out the
id
field from it.Similarly, destructure the second argument (
context
) to access thedataSources
property.subgraph-locations/resolvers.js__resolveReference: ({id}, {dataSources}) => {// TODO},The body of the reference resolver function needs to return all the entity fields that this subgraph defines. To do this, we'll use the
LocationsAPI
data source and itsgetLocation
method. It returns aLocation
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 thesubgraph-locations/datasources/LocationsApi.js
file.
And with that, our graph is now fully set up to handle referencing entities!
Okay, we should be ready to query our supergraph in Studio, and watch the magic of the router associating data between our subgraphs!
Let's get to building the GetLatestReviews
query we agreed upon earlier with the frontend team. We'll add our fields... wait a minute, where did our location
field go? Wasn't this working great locally on Sandbox? What happened?
We forgot to publish our reviews
subgraph schema 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 variables for the reviews
subgraph.
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 query in Studio.
query GetLatestReviews {latestReviews {idcommentratinglocation {name}}}
Note: If you see red squiggly lines below the location
field on latestReviews
, try refreshing the page. You may have been faster than the supergraph composition!
And we can see all our data is coming back from both the locations
and reviews
subgraphs!
We should see a response like this:
Let's update our schema agreement checklist and check off the location field we just added to the Review type.
Practice
__resolveReference
function?Key takeaways
- We can reference an entity in one subgraph as the return value for a type's field.
- Any subgraph that contributes fields to an entity needs to define a
__resolveReference
resolver function for that entity. This resolver is called when the router needs to resolve references to that entity made from within other subgraphs.
Up next
Awesome work. Our subgraphs aren't so isolated anymore. And we're almost done checking off the fields in our schema agreement. In the next lesson, we'll contribute the last two fields: reviewsForLocation
and overallRating
.
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.