DEV Community

Cover image for Tutorial: Apollo Client with React and TypeScript
Akos
Akos

Posted on • Originally published at akoskm.com

Tutorial: Apollo Client with React and TypeScript

In this tutorial, we’ll find out how we can use Apollo Client with React and TypeScript to power our front-end apps. We love Apollo Client because of its built-in robust state management, in-memory caching, and error handling capabilities. To keep the demo simple we’re not going to write any backend code for this presentation, and use the publicly available SpaceX GraphQL API.

Installing Apollo Client with React and TypeScript

To make our lives simpler we’re also going to start with create-react-app, specifically with a typescript template:

yarn create react-app apollo-client-react-typescript --template typescript
Enter fullscreen mode Exit fullscreen mode

Next, we’re going to install the Apollo Client alongside GraphQL:

yarn add @apollo/client graphql
Enter fullscreen mode Exit fullscreen mode

The @apollo/client package contains the state management/caching and error handling while graphql parses the GraphQL queries.

Now that we have these packages installed we’ll create the building blocks that are necessary to communicate with the GraphQL endpoint.

Data fetching with Apollo Client

Building a client

The Apollo Client is the object where we specify the details of our connection.

To create an ApolloClient we must set the following parameters in the constructor:

  • uri: GraphQL URL we want to query when using ApolloClient
  • cache: a cache configuration to tell Apollo Client how to store the results on your machine

Our Apollo Client will look like this:

const client = new ApolloClient({
  uri: 'https://api.spacex.land/graphql/',
  cache: new InMemoryCache()
});
Enter fullscreen mode Exit fullscreen mode

Building an Apollo Provider

To be able to use this Apollo Client instance inside a React Component, we have to wrap the React component with a specific component called ApolloProvider. This accepts a single prop: client that is an instance of an ApolloClient.

Connecting the Apollo Provider to the React Component

It’s time to pass our instance of ApolloClient to the ApolloProvider component.

The best place to do this is a top-level component (such as index.tsx in our app) so all child components will have access to the Apollo client through the same provider. Open index.tsx, our top-level component and wrap it with ApolloProvider while passing in the ApolloClient instance:

import App from './App';
import { ApolloProvider } from '@apollo/client/react';
import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
  uri: 'https://api.spacex.land/graphql/',
  cache: new InMemoryCache()
});

ReactDOM.render(
  <React.StrictMode>
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  </React.StrictMode>,
  document.getElementById('root')
);
Enter fullscreen mode Exit fullscreen mode

Querying data with Apollo Client and TypeScript

Now that we wrapped the App React Component with ApolloProvider, we’re ready to make some queries. GraphQL, thanks to its GraphiQL interface provides an easy way to discover GraphQL APIs.

If you haven’t decided what you want to query for, visit the interactive explorer of the SpaceX API here: https://api.spacex.land/graphql/.

Let’s say we want to create a query that returns the id, name, the Wikipedia link, and a brief description of each SpaceX rocket.

If you’re new to the GraphQL syntax I suggest you visit https://graphql.org/learn/queries/.

The query would look like this:

{
  rockets {
    id
    name
    wikipedia
    description
  }
}
Enter fullscreen mode Exit fullscreen mode

Let’s create a type that describes a single rocket:

interface RocketData {
  id: string;
  name: string;
  wikipedia: string;
  description: string;
}
Enter fullscreen mode Exit fullscreen mode

Don’t forget, we’re going to receive an array of rockets here, so let’s create a type for that as well:

interface RocketsResult {
  rockets: Array<RocketData>;
}
Enter fullscreen mode Exit fullscreen mode

To run this query we’re going to use the useQuery hook and the gql function, provided by the Apollo Client:

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

const ROCKETS = gql`
  rockets {
    id
    name
    wikipedia
    description
  }
`;

function App() {
  const { loading, error, data } = useQuery<RocketsResult>(ROCKETS);

  return (
    <>
      <h1>SpaceX Rockets</h1>
      {loading || !data ? (<p>Loading...</p>) :
        data.rockets.map(rocket => (
          <div key={rocket.id}>
            <h2><a href={rocket.wikipedia}>{rocket.name}</a></h2>
            <p>{rocket.description}</p>
          </div>
        ))
      }
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

useQuery’s first type is the type that corresponds to the data structure we’re going to receive from the GraphQL endpoint.

The useQuery hook also returns an object with the following properties:

loading: indicates if Apollo Client is still waiting for the query results
error: if the query resulted in error(s)
data: the results of the GraphQL Query
Now you can run the app with yarn start and you should see something similar in your browser:

page loading

Modifying data with Apollo Client

Now that we’ve learned how to fetch data with Apollo Client it would be nice to see how we can update things at the other end of the GraphQL endpoint.

SpaceX API provides a simple interface for adding users.

When writing a mutation query we use the same gql function we used for the query:

const ADD_USER = gql`
  mutation InsertUser($name: String!) {
    insert_users(objects: { name: $name }) {
      returning {
        id
        name
      }
    }
  }
`;
Enter fullscreen mode Exit fullscreen mode

You might’ve already noticed that, unlike the query, the mutation has a function-like signature. In case of insert_user it accepts objects: { name: $name }.

Let’s define some TypeScript types to describe what kind of data we’re getting back from this mutation. These types are going to depend a lot on how the GraphQL endpoint formats its response. In our case, the types are the following:

interface UserDetails {
  id: string;
  name: string;
}

interface AddUserResponse {
  returning: Array<UserDetails>;
}
Enter fullscreen mode Exit fullscreen mode

The useMutation query has the following signature:

  const [addUser, { data: userData }] = useMutation<
    { insert_users: AddUserResponse }
  >(ADD_USER);
Enter fullscreen mode Exit fullscreen mode

Important to note that the mutation is not called when we define the hook. It returns a function - in our case addUser - that we should call with the necessary parameters. Same as for the userQuery hooks, the type you pass into useMutation should match the response you get back from the server after you call this mutation.

Now let’s put it all together:

interface UserDetails {
  id?: string;
  name: string;
}

interface AddUserResponse {
  returning: Array<UserDetails>;
}

function App() {
  const [name, setName] = useState('');

  const [addUser, { data: userData }] = useMutation<
    { insert_users: AddUserResponse }
  >(ADD_USER);

  function handleOnChange(e: React.ChangeEvent<HTMLInputElement>) {
    setName(e.target.value);
  }

  async function handleOnSubmit(e: React.FormEvent) {
    e.preventDefault();
    await addUser({ variables: { name }});
    setName('');
  }

  return (
    <>
      <h1>Users</h1>
      <form onSubmit={handleOnSubmit}>
        <label htmlFor="username">Name: </label>
        <input required name="username" type="text" onChange={handleOnChange} value={name}/>
        <button type="submit">Add User</button>
        <p>
          New User ID: {userData && userData.insert_users.returning[0].id}
        </p>
      </form>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Here’s what you should see in your browser:
update user data

Congratulation, you just added a new user to SpaceX API’s Database!

This Demo project is available on GitHub.

What’s next? If you would like to further explore the capabilities of Apollo GraphQL I suggest checking out their Subscriptions interface and Fragments logic.

Are you already using GraphQL in some of your projects? Do you think it's going to replace REST?

Top comments (0)