Odyssey

Voyage I: Federation from Day One

Intro to FederationProject setupAgreeing on a schemaBuilding out the subgraphsManaged federation & the supergraphPublishing the subgraphs with RoverHow the router resolves dataRouter configuration and UplinkConnecting data using entitiesDefining an entityEntities and the query planReferencing an entityContributing to an entityPutting it all together
3. Agreeing on a schema
4m

Overview

Our starter code is all set up, and we're ready to design FlyBy's supergraph!

We'll use a schema-first approach, where we collaborate with the frontend team to agree on FlyBy's data requirements. With that schema agreement in place, the lovely frontend team can go off and do their thing on the client side while we focus on building the supergraph.

In this lesson, we will:

  • Examine the FlyBy frontend requirements to identify the data needs of our application
  • Decide how to split up those data needs across multiple subgraphs

Meeting with the frontend

Let's get to the planning meeting with the frontend team. They've put together mock-ups for a few different pages, and everyone's excited to work together to make them a reality. Let's jump right into the data requirements.

The homepage

We've learned that FlyBy's homepage should display a list of interplanetary locations. In addition to each location's name and photo, we'd also like to show its overall review rating and a snippet of its latest review.

The team also wants to show a selection of the most recently submitted reviews across all locations, to highlight recent positive experiences. More space travel is good for business.

We can annotate the mock-up from the frontend team to show the different pieces of data required by the UI:

An annotated mock-up of the FlyBy home page. The pieces of data called out are review comment, overall rating, location name, and location photo.

Our gears are already turning! Together, we write an example query for this page, so that the frontend team has something to code against while we build out the backend.

query GetHomePageLocationsAndReviews {
latestReviews {
id
comment
rating
location {
name
}
}
locations {
id
name
overallRating
photo
reviewsForLocation {
id
comment
rating
}
}
}

This query has two discrete parts: one for the latest reviews and one for the list of locations.

The query above is annotated to show groupings of reviews data and locations data

We're already beginning to see how we might draw subgraph boundaries around our data. But let's continue with the other view our frontend team has planned.

The location details page

The next mock-up is for the location details page, which shows information about the destination, as well as all of its reviews.

An annotated mock-up of the FlyBy location details page. The data that's called out includes location name, overall rating, location photo, location description, list of reviews, and a form to add a new review.

The location details page needs data for one particular location, as well as other details and reviews for the location.

query GetLocationDetails($locationId: ID!) {
location(id: $locationId) {
id
name
description
photo
overallRating
reviewsForLocation {
id
comment
rating
}
}
}

This page also needs a way for users to submit new reviews. We'll write a mutation that allows us to do just that.

mutation SubmitReview($locationReview: LocationReviewInput) {
submitReview(locationReview: $locationReview) {
code
success
message
locationReview {
id
comment
rating
}
}
}

Let's break down what's going on in this mutation. (For more on mutations, check out Lift-off IV: Mutations.)

To submit a new review, we need some input from the user. We decide our mutation will receive a $locationReview parameter of a type we'll call LocationReviewInput, which will include the comment and rating for the new review, as well as the associated locationId:

LocationReviewInput {
comment: String!
rating: Int!
locationId: String!
}

With that in mind, here's what our example mutation for the frontend team looks like so far:

mutation SubmitReview($locationReview: LocationReviewInput) {
submitReview(locationReview: $locationReview) {
# TODO!
}
}

After a user submits a new location review, we decide we'll return all of the data for that new review, along with a status code, a success boolean, and an optional message to describe any errors that might occur. (Following the convention we learned in Lift-off IV, we'll create a new type for these fields called SubmitReviewResponse.)

mutation SubmitReview($locationReview: LocationReviewInput) {
submitReview(locationReview: $locationReview) {
code
success
message
locationReview {
id
comment
rating
}
}
}

The schema agreement

Putting together all the data requirements from both the homepage and the location details page, we can draw up the schema we've agreed on with the frontend team.

A schema diagram showing all the fields for the FlyBy graph. Extended description below.

Schema agreement for the FlyBy graph:

# schema entry points
type Query {
latestReviews: [Review!]!
locations: [Location!]!
location(id: ID!): Location
}
type Mutation {
submitReview(locationReview: LocationReviewInput): SubmitReviewResponse
}
# type definitions
type Location {
id: ID!
name: String!
description: String!
photo: String!
reviewsForLocation: [Review]!
overallRating: Float
}
type Review {
id: ID!
comment: String
rating: Int
location: Location
}
type LocationReviewInput {
comment: String!
rating: Int!
locationId: String!
}
type SubmitReviewResponse {
code: Int!
success: Boolean!
message: String!
locationReview: Review
}

We'll use this as a checklist throughout the course, to track our progress as we build out the supergraph.

Now it's time to say goodbye to the frontend team and get to work on the backend.

We can see that the types and fields focus on two main objects: locations and reviews. We'll separate each of these concerns into its own subgraph, which can be built and maintained by its own team.

Let's say hello to our two subgraph teams!

Separating our concerns

The locations subgraph team deals with all of the data about what space locations we have to offer. The locations subgraph will handle the Query entry points for location and locations, and it will supply details for a specific location's id, name, photo, and description.

The reviews subgraph team is in charge of data for what explorers share about their visits. The reviews subgraph will provide the latest reviews, handle new review submissions, and supply data about a specific review.

Let's annotate our schema agreement to show whether each field will be resolved by the locations subgraph or the reviews subgraph:

The schema diagram from earlier, with each field highlighted to show whether it belongs to the locations or reviews subgraph. Extended description below.

Schema agreement for the FlyBy graph, updated with comments to show which subgraph will be responsible for resolving each field:

# schema entry points
type Query {
latestReviews: [Review!]! # Reviews subgraph
locations: [Location!]! # Locations subgraph
location(id: ID!): Location # Locations subgraph
}
type Mutation {
submitReview(locationReview: LocationReviewInput): SubmitReviewResponse # Reviews subgraph
}
# type definitions
type Location { # Locations subgraph
id: ID! # Locations subgraph
name: String! # Locations subgraph
description: String! # Locations subgraph
photo: String! # Locations subgraph
reviewsForLocation: [Review]! # Reviews subgraph
overallRating: Float # Reviews subgraph
}
type Review { # Reviews subgraph
id: ID! # Reviews subgraph
comment: String # Reviews subgraph
rating: Int # Reviews subgraph
location: Location # Reviews subgraph
}
type LocationReviewInput { # Reviews subgraph
comment: String! # Reviews subgraph
rating: Int! # Reviews subgraph
locationId: String! # Reviews subgraph
}
type SubmitReviewResponse { # Reviews subgraph
code: Int! # Reviews subgraph
success: Boolean! # Reviews subgraph
message: String! # Reviews subgraph
locationReview: Review # Reviews subgraph
}

Did you notice?

Wait—what about these two other fields? reviewsForLocation and overallRating are fields on the Location type, but do they really belong in the locations subgraph?

Well... we can do whatever we want here. But in our case, if we think about our different subgraphs and their separation of concerns, it makes more sense for overallRating and reviewsForLocation to live in the reviews subgraph. After all, these fields have more to do with reviews than they do with locations, even though they happen to be fields on the Location type.

But this separation raises a question: how do we connect the fields of a single object when they're resolved by multiple subgraphs?

This is an important question that's at the very heart of Apollo Federation, and it's what we'll spend the rest of this course trying to answer.

Practice

Which of the following statements about subgraph schemas are true?

Key takeaways

  • Annotating UI mock-ups is one way to collaborate with the frontend team and implement a schema-first design process.
  • Agreeing on your schema structure at the start of a new project means your frontend and backend teams can work in parallel.
  • To decide how to split your schema into multiple subgraphs, you can group types and fields related to similar concerns.
  • Each subgraph schema contains only the types and fields that particular subgraph is responsible for resolving.

Up next

With our schema agreement in place and our subgraphs mapped out, we're ready to start building FlyBy's supergraph! So next, let's set up the locations and reviews subgraphs.

Previous
Next

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.

              supergraph

              A unified, federated graph composed of separate GraphQL APIs using Apollo Federation. Enables a microservices architecture that exposes a unified GraphQL API to clients.

              supergraph

              A unified, federated graph composed of separate GraphQL APIs using Apollo Federation. Enables a microservices architecture that exposes a unified GraphQL API to clients.

              subgraph

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              subgraph

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              graph

              A schema-based data model representing how different data elements interconnect and can be accessed.

              supergraph

              A unified, federated graph composed of separate GraphQL APIs using Apollo Federation. Enables a microservices architecture that exposes a unified GraphQL API to clients.

              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              subgraph

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              subgraph

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              subgraph

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              subgraph

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              subgraph

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              subgraph

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              subgraph

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              subgraph

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              graph

              A schema-based data model representing how different data elements interconnect and can be accessed.

              subgraph

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              subgraph

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              subgraphs

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              subgraph

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              Apollo Federation

              Apollo’s implementation of GraphQL Federation—an architecture for orchestrating multiple APIs into a single GraphQL API.

              subgraphs

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              subgraph schema

              A schema for a subgraph server. A subgraph schema must be compliant with the GraphQL and Apollo Federation specs to be composed into a supergraph.

              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              subgraphs

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              supergraph

              A unified, federated graph composed of separate GraphQL APIs using Apollo Federation. Enables a microservices architecture that exposes a unified GraphQL API to clients.

              subgraphs

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              NEW COURSE ALERT

              Introducing Apollo Connectors

              Connectors are the new and easy way to get started with GraphQL, using existing REST APIs.

              Say goodbye to GraphQL servers and resolvers—now, everything happens in the schema!

              Take the course