Overview
Let's continue building our accounts
subgraph! The accounts
subgraph is responsible for all things user profile-related, and we listed out all of the types and fields we wanted to migrate over to this subgraph. In this list, we have the User
interface and its corresponding implementing types (Host
and Guest
). That's where we'll start!
Tip: First time seeing GraphQL interfaces? Check out the Intermediate Schema Design side quest for more details on what they are and how they work.
In this lesson, we will:
- Learn how to define an interface across multiple subgraphs
- Review what an entity is and how to define entities
- Review how to contribute fields to an entity
The User
interface
Let's start with the User
interface. We can find its definition in the monolith/schema.graphql
file.
"Represents an Airlock user's common properties"interface User {id: ID!"The user's first and last name"name: String!"The user's profile photo URL"profilePicture: String!}
We know that the interface needs to exist in the accounts
subgraph, since it's related to accounts and users. So let's go ahead and copy the definition, and paste it into the accounts
subgraph schema.
"Represents an Airlock user's common properties"interface User {id: ID!"The user's first and last name"name: String!"The user's profile photo URL"profilePicture: String!}
What about in the monolith
subgraph? Well, we still need to keep the User
interface defined there. We reference it as a return type for the Review.author
field, and we also implement the interface for the Host
and Guest
types.
However, we don't need to keep all the extra fields that are the responsibility of the accounts
subgraph! We can remove both name
and profilePicture
.
"Represents an Airlock user's common properties"interface User {id: ID!- "The user's first and last name"- name: String!- "The user's profile photo URL"- profilePicture: String!}
We do still need to keep the id
field, because that's the bare minimum we need to identify a specific instance of a user. Like a stub, similar to when we reference an entity in Voyage I.
Make no mistake though! The User
interface is not an entity. An interface is actually an example of a value type. Value types are types that are reused and shared across multiple subgraphs. These types can be object types, enums, unions, or interfaces (like our case!).
In Federation 2, interface definitions can be shared between subgraphs by default, and those definitions can differ in each subgraph. This is how we can remove the name
and profilePicture
fields from the User
interface definition in the monolith
subgraph!
Now that we're got our User
interface squared away in both subgraphs, let's move on to the implementing types, Host
and Guest
.
Creating entities for Host
and Guest
In the previous course (Voyage I), we talked about how entities are object types that can resolve their fields across multiple subgraphs. Let's review what else we learned about entities:
- We can define entities in subgraphs, and these subgraphs can contribute fields to the entity and resolve these fields independently.
- An entity can be referenced by using it as the return type for a field.
The Host
and Guest
types are perfect candidates for entities! They each have fields that different subgraphs can contribute to.
✏️ The Host
entity
Let's first take a look at the Host
type and its fields. For each field, we've added a comment on which subgraph should be responsible for that field, based on the separation of concerns principle.
type Host implements User {id: ID! # this will be the key field, a unique identifier for a particular instance of a Hostname: String! # accounts subgraphprofilePicture: String! # accounts subgraphprofileDescription: String! # accounts subgraphoverallRating: Float # reviews subgraph, eventually}
Using the plan above, we'll need to do the following:
- Define the
Host
type as an entity in both subgraphs, using theid
field as the@key
field. - Move three fields (
name
,profilePicture
andprofileDescription
) over to theaccounts
subgraph, which will be responsible for contributing those fields to theHost
entity. - The
monolith
subgraph will contribute theoverallRating
field (eventually, thereviews
subgraph will, but let's take it one step at a time!).
Let's get to it!
Tip: Try using side-by-side windows for this process and throughout the course. We'll be splitting off types and fields from the monolith
subgraph schema (on the left), and moving or duplicating them over to the accounts
subgraph schema (on the right).
In the
accounts
subgraph, let's create theHost
type as an entity. Remember that it needs to implement theUser
interface.To make it an entity, we'll add the
@key
directive, with theid
as its primary key.subgraph-accounts/schema.graphqltype Host implements User @key(fields: "id") {id: ID!}From the
monolith
subgraph schema, let's move the three fields over to theaccounts
subgraph schema:name
,profilePicture
andprofileDescription
.subgraph-accounts/schema.graphqltype Host implements User @key(fields: "id") {id: ID!"The user's first and last name"name: String!"The user's profile photo URL"profilePicture: String!"The host's profile bio description, will be shown in the listing"profileDescription: String!}We're moving these fields over, so don't forget to remove them from the
monolith
subgraph schema!monolith/schema.graphqltype Host implements User {id: ID!- "The user's first and last name"- name: String!- "The user's profile photo URL"- profilePicture: String!- "The host's profile bio description, will be shown in the listing"- profileDescription: String!"The overall calculated rating for the host"overallRating: Float}Lastly, we'll need to define the
Host
type in themonolith
subgraph schema as an entity as well.monolith/schema.graphql"A host is a type of Airlock user. They own listings."type Host implements User @key(fields: "id") {id: ID!"The overall calculated rating for the host"overallRating: Float}
That's it for the Host
entity!
✏️ The Guest
entity
Let's use the same process for the Guest
entity, labelling each field with which subgraph should be responsible for it.
"A guest is a type of Airlock user. They book places to stay."type Guest implements User {id: ID! # this will be the key field, a unique identifier for a particular instance of a Guestname: String! # accounts subgraphprofilePicture: String! # accounts subgraphfunds: Float! # payments subgraph, eventually}
We can see that it's very similar to what we did for the Host
entity!
- Define the
Guest
type as an entity in both subgraphs, using theid
field as the@key
field. - Move two fields (
name
andprofilePicture
) over to theaccounts
subgraph, which will be responsible for contributing those fields to theGuest
entity. - The
monolith
subgraph will contribute thefunds
field (eventually, thepayments
subgraph will, but let's take it one step at a time!).
By the end of those steps, our subgraph schemas for the Guest
entity should look like this:
"A guest is a type of Airlock user. They book places to stay."type Guest implements User @key(fields: "id") {id: ID!"The user's first and last name"name: String!"The user's profile photo URL"profilePicture: String!}
"A guest is a type of Airlock user. They book places to stay."type Guest implements User @key(fields: "id") {id: ID!"Amount of money in the guest's wallet"funds: Float!}
Reviewing the schema plan
Going back to our schema plan, we can check off the User
, Host
and Guest
types that we've added to the accounts
subgraph!
Practice
Key takeaways
- Value types are types that are reused and shared across multiple subgraphs. Interfaces are an example of a value type.
- Value type schema definitions can differ across subgraphs, in Federation 2.
Up next
Phew! We've seen value types in action, and made a bunch of changes to both of our schema files. In the next lesson, we'll publish our changes and test out our updated supergraph.