Odyssey

Lift-off II: Resolvers

Journey of a GraphQL queryExploring our dataApollo RESTDataSourceImplementing our RESTDataSourceThe shape of a resolverImplementing query resolversConnecting the dots in server-landQuerying live dataErrors! When queries go sidewaysJourney's end
1. Journey of a GraphQL query
3m
You're currently on an older version of this course. View course changelog.

👋 Welcome to Part II of our Lift-off series!

In Lift-off I, we built the homepage grid feature for the Catstronauts app, our learning platform for cats who want to explore the universe. We designed that feature with a schema-first approach and mocked static data. We displayed a single mocked entry multiple times to populate the cards of our homepage grid.

Now it's time to connect this app to real live data!

By the end of this course, your Catstronauts homepage will look like this:

Screenshot of the Catstronauts homepage in a browser showing live data

Ignition sequence...

Prerequisites

Our app uses Node.js on the backend and React on the frontend. For this course, we'll be working only on the backend.

Note: In this course, we're using Apollo Server 3. If you need to reference the Apollo documentation while going through the course, make sure you're on the v3 documentation set!

Clone the repository

In the directory of your choice with your preferred terminal, clone the app's starter repository:

git clone -b v1 https://github.com/apollographql/odyssey-lift-off-part2

Note: The git clone above command might look a bit different than what you're used to. This course uses v1 of the starter code repo. Click here to access the most up-to-date version of this course.

Task!

Project structure

This repo picks up where Lift-off I left off. Our project is a full-stack app with the backend app in the server/ directory and the frontend app in the client/ directory.

You'll also find a final/ folder that contains the final state of the project once you've completed the course. Feel free to use it as a guide!

Here's the file structure:

📦 odyssey-lift-off-part2
┣ 📂 client
┃ ┣ 📂 public
┃ ┣ 📂 src
┃ ┣ 📄 README.md
┃ ┣ 📄 package.json
┣ 📂 server
┃ ┣ 📂 src
┃ ┃ ┣ 📄 index.js
┃ ┃ ┣ 📄 schema.js
┃ ┣ 📄 README.md
┃ ┣ 📄 package.json
┣ 📂 final
┃ ┣ 📂 client
┃ ┣ 📂 server
┗ 📄 README.md

Now, open the repository in your favorite IDE.

Note: The examples in this course use npm, but you're welcome to use yarn if you prefer.

Let's start with the server app.

In a terminal window, navigate to the repo's server directory and run the following to install dependencies and run the app:

npm install && npm start

If all goes well, you'll see the installation complete and a message in the console indicating that the server is running.

Task!

Next, the client app.

In a new terminal window, navigate to the repo's client directory and run the following to install dependencies and start the app:

npm install && npm start

The console should show a bunch of output and a link to the running app at localhost:3000. You can navigate to http://localhost:3000 in the browser and see our homepage, which shows one Track card repeating a few times. This is the mock data we set up in Part I.

Task!

To understand what our GraphQL server is missing to work with live data, and how it will know where to fetch what, let's take a step back and explore the journey of a GraphQL query.

Journey of a GraphQL query

Centered text 'The Journey of a GraphQL Query' with accompanying doodles of GraphQL components around

In client-land

Our web app needs to fetch remote data to populate its homepage.

To get that data, it sends a query to our GraphQL server. The app shapes the query as a string that defines the selection set of fields it needs. Then, it sends that query to the server in an HTTP POST or GET request.

Hand-drawn illustration depicting client-land with a browser sending a query to server-land across a network
How does our Catstronauts client send queries to our GraphQL server?

In server-land

When our server receives the HTTP request, it first extracts the string with the GraphQL query. It parses and transforms it into something it can better manipulate: a tree-structured document called an AST (Abstract Syntax Tree). With this AST, the server validates the query against the types and fields in our schema.

If anything is off (e.g. a requested field is not defined in the schema or the query is malformed), the server throws an error and sends it right back to the app.

Hand-drawn illustration depicting server-land with the GraphQL server receiving a query and going through the necessary steps
Which of these are actions that our GraphQL server takes when it receives a request?
Which of these are situations where our GraphQL server will throw an error?

In this case, the query looks good, and the server can "execute" it. Meaning, the server can continue its process and actually fetch the data. The server walks down the AST.

For each field in the query, the server invokes that field's resolver function. A resolver function's mission is to "resolve" its field by populating it with the correct data from the correct source, such as a database or a REST API.

Hand-drawn illustration depicting a resolver function retrieving data from data-land
Which of these are responsibilities of a resolver function?

As all of the query's fields are resolved, the data is assembled into a nicely ordered JSON object with the exact same shape as the query.

The server assigns the object to the HTTP response body's data key, and it's time for the return trip, back to our app.

Hand-drawn illustration depicting the server returning a response back to the browser in client-land
When a query executes successfully, which of these is included in the object returned by the GraphQL server?

Back to client-land

Our client receives the response with exactly the data it needs, passes that data to the right components to render them, and voilà, our homepage is displaying its cards from remote data.

Hand-drawn illustration depicting the browser rendering the data

And that's the journey of a GraphQL query!

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.

              Apollo Server

              An open-source library for server-side GraphQL operation handling. It can be used as a monolithic GraphQL server or a subgraph server within a supergraph.

              GraphQL server

              A server that contains a GraphQL schema and can resolve client-requested operations that are executed against that schema.

              query

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

              GraphQL server

              A server that contains a GraphQL schema and can resolve client-requested operations that are executed against that schema.

              selection set

              The part of a GraphQL query that specifies the fields and subfields to retrieve from the server. Selection sets define the structure and shape of the data response.

              The following example query has four selection sets:

              query GetWeatherForecast {
              weatherForecast {
              currentConditions {
              conditions
              temperature
              }
              dailyForecast {
              highTemperature
              lowTemperature
              conditions
              }
              timestamp
              }
              }

              The root selection set contains the weatherForecast field. weatherForecast has its own selection set with three fields. Two of those fields—currentConditions and dailyForecast— contain selection sets themselves.

              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
              }
              GraphQL

              An open-source query language and specification for APIs that enables clients to request specific data, promoting efficiency and flexibility in 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.

              document

              A file or request string that contains one or multiple definitions of a GraphQL type system and can be interpreted by a GraphQL execution engine.

              query

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

              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
              }
              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
              }
              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.

              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
              }
              query

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

              resolver

              A function that populates data for a particular field in a GraphQL schema. For example:

              const resolvers = {
              Query: {
              author(root, args, context, info) {
              return find(authors, { id: args.id });
              },
              },
              };
              query

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

              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
              }
              GraphQL

              An open-source query language and specification for APIs that enables clients to request specific data, promoting efficiency and flexibility in 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.

              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