Skip to content
Lydia Hallie theavocoder
GraphQL / Guide

React + Apollo Client + GraphQL Yoga

This guide connects three pieces: a GraphQL Yoga server that understands a schema, an Apollo Client that sends queries and caches the result, and a React component that renders what comes back. The goal is to see the whole path from a field in a schema to a value on the screen.

The server

Yoga turns a schema and a set of resolvers into a fetchable endpoint. The schema declares what can be asked for. The resolvers decide what the answer is.

import { createServer } from "node:http";
import { createSchema, createYoga } from "graphql-yoga";

const lessons = [
  { id: "1", title: "Variables", path: "/complete-javascript/2018/12/17/variables", runtime: "reading" }
];

const schema = createSchema({
  typeDefs: `
    type Query {
      lesson(id: ID!): Lesson
    }
    type Lesson {
      id: ID!
      title: String!
      path: String!
      runtime: String
    }
  `,
  resolvers: {
    Query: {
      lesson: (_, { id }) => lessons.find((lesson) => lesson.id === id)
    }
  }
});

createServer(createYoga({ schema })).listen(4000);

The server is now listening on port 4000. The GraphQL endpoint is available at /graphql, so the full address is http://localhost:4000/graphql.

The client

Apollo Client needs two things: a link that knows where the server lives, and a cache that stores the results. The provider makes the client available to every component below it.

import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client";
import { ApolloProvider } from "@apollo/client/react";

const client = new ApolloClient({
  link: new HttpLink({ uri: "http://localhost:4000/graphql" }),
  cache: new InMemoryCache()
});

export function App({ children }) {
  return <ApolloProvider client={client}>{children}</ApolloProvider>;
}

The query

The gql tag parses the query string. useQuery runs it, tracks loading and error states, and returns the data in the shape the query asked for.

import { gql, useQuery } from "@apollo/client";

const LESSON = gql`
  query Lesson($id: ID!) {
    lesson(id: $id) {
      title
      path
    }
  }
`;

export function Lesson({ id }) {
  const { data, loading, error } = useQuery(LESSON, { variables: { id } });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Something went wrong.</p>;

  return <h2>{data.lesson.title}</h2>;
}

What to notice

The component does not know how the data is stored. It only knows the shape of the query. The server does not know how the component renders. It only knows the schema. That separation is the point of GraphQL, and it is why the schema is worth designing before the first resolver is written.

The cache is the other half of the story. Apollo can reuse a result when the same object is requested again, which keeps the UI responsive and reduces repeated network work.

Where to go next

Read the Objects lesson for the data shapes on the server, then try the Promises lesson to understand the async work behind a query.

References and further reading