Belinda Ijeoma Frontend engineer | Technical writer | Tech enthusiast

Data retrieval in GraphQL with react-apollo

4 min read 1322

Data retrieval in GraphQL with React Apollo

In this article, we will explore how to use the GraphQL query language with Apollo Client to efficiently and seamlessly fetch data from a server. By the end of your reading, you will learn how to use and install GraphQL and Apollo client, and two different approaches for how to perform query and mutation operations within react-apollo.

GraphQL

GraphQL is a query language that uses a defined system to describe how a user should ask for data from an API. GraphQL requires that a user specify the exact data that needs to be transferred — most often from the server — which will then be loaded to the client side.

Before we learn about how specific query operations can be performed with Apollo, we will review some of the basic actions and operations that can be performed within the GraphQL query library.

1. Query

A GraphQL query operation is concerned with basic data fetching from the server side.

  {
    query getItems {
      Items {
        id
        chair
        stool
       }
     }
  }

The above is a GraphQL query with name getItems, that fetches id, chair, and stool.

2. Mutation

Adding the mutation keyword performs basic CRUD (create, read, update and delete) operations in a GraphQL application.

{
    mutation addUser(name: String!, email: String!){
      addUser(name: $name, email: $email){
        id
        name
        email
        created_at
      }
    }
  }

The above addUser mutation returns a user’s name, id, email, and create_at fields when the user’s name and email is specified.

3. Subscription

This is an event-based action that involves data transfer from the server to the client side when a particular event is executed. To create a subscription in GraphQL, we need to add the subscription type to our schema:

const typeDefs = gql`
  type Subscription {
    bookAdded: Book
  }`

The next step is to create a resolver. Pubsub is notified of an event in this case from within a mutation.

const BOOK_ADDED = 'BOOK_ADDED';

const resolvers = {
  Subscription: {
    bookAdded: {
      subscribe: () => pubsub.asyncIterator([BOOK_ADDED]),
    },
  },

  Mutation: {
    addBook(root, args, context) {
      pubsub.publish(BOOK_ADDED, { bookAdded: args });
      return postController.addBook(args);
    },
  },
};

The subscription is triggered by a publish call inside the mutation.

Apollo

Apollo serves as a state management library for local and remote data storage in a GraphQL application. Some of the basic operations that you can perform with the help of Apollo include: fetching, local state storage, and caching. The Apollo client also has a built-in integration with React that makes development much easier.

Some basic features of Apollo client include:

Declarative data fetching

Apollo client allows a user to specify the exact data needed from an application programming interface. React uses a useQuery Hook that enables us perform data retrieving and data fetching operations in a GraphQL application. An example from the official documentation can be found below:

function Feed() {
    const { loading, error, data } = useQuery(GET_DOGS);
    if (error) return <Error />;
    if (loading || !data) return <Fetching />;

    return <DogList dogs={data.dogs} />;
  }

With the help of the useQuery Hook, we are able to fetch data from the GraphQL server that will lead to a UI update to reflect any changes.

Caching

Aside from the main fetching operations that can be performed with GraphQL, intelligent data caching operations can also be performed with with little to no configuration.

Below is an Apollo client configuration for data caching:

 import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
  cache: new InMemoryCache()
});

Other benefits that come with Apollo client include:

  1. Support for modern React Hooks
  2. Compatibility
  3. Strong community support
  4. Pagination

Installation and use of GraphQL and Apollo Client

If you have not set up your React application, start by running the following:

npx create-react-app

To make use of GraphQL and Apollo in your React application, you will need to install the following dependencies:

npm install apollo-boost graphql react-apollo

Your React application with GraphQL is now set up and ready for use!

To create a connection, first create an index.js file and add the following snippet:

import ApolloClient from "apollo-boost";
import { ApolloProvider } from 'react-apollo';

const client = new ApolloClient({
    uri: //graghql server url should be here
  });

Next, wrap your app component with the ApolloProvider, passing the client as props:

ReactDOM.render(
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>,
    document.getElementById("root")
  );

At the beginning, we talked about basic operations that you can perform with GraphQL including query and mutation. Now let’s, look at how to perform some of these operations with Apollo using the useQuery Hook approach and the render props approach.

Queries

GraphQL queries involve reading and fetching of data. We can take two approaches in performing this operation with React Apollo: the useQuery Hook approach and the render props approach.

useQuery Hook approach

First, let’s create a GraphQL query and name it getItems as shown below:

import React from "react";
import { useQuery } from "react-apollo";
import { gql } from "apollo-boost";

const GET_ITEMS = gql`
  query GetItems {
    items {
      id
          oneitem
    }
  }
`;

Next, create a functional component and pass the GraphQL query to the useQuery Hook as follows:

function DisplayItems() {
  const { loading, error, data } = useQuery(GET_ITEMS);

  if (loading) return 'Loading...';
  if (error) return `Error! ${error.message}`;

  return (
    <select name="items">
      {data.items.map(item => (
        <option key={item.id} value={item.oneitem}>
          {item.oneitem}
        </option>
      ))}
    </select>
  );
}

The application will update when the new data is fetched or when an error occurs to reflect the new changes.



Render props approach

For the render props approach, the first step remains the same except for an additional importation of query from react-apollo that we previously installed:

import React from "react";
import { Query } from "react-apollo";
import { gql } from "apollo-boost";

const GET_ITEMS = gql`
  query GetItems {
    items {
      id
          oneitem
    }
  }
`;

Next, we will make use of query by passing the created GraphQL query to it and using it as follows:

function DisplayItems() {

  if (loading) return 'Loading...';
  if (error) return `Error! ${error.message}`;

  return (
    <Query query={GET_ITEMS}>
    <select name="items">
      {data.items.map(item => (
        <option key={item.id} value={item.oneitem}>
          {item.oneitem}
        </option>
      ))}
    </select>
    </Query>
  );
}

Just like in the hooks approach, the application will either update to reflect the new data or return an error.

Mutation

Mutation involves performing creating, updating, and deleting operations. As is the case with queries, we can make use of the hooks approach and render props approach when dealing with mutation.

Hooks approach

First let’s import the dependencies including useMutation imported from react-apollo.

import React, { useState } from 'react';
import { useMutation } from 'react-apollo';
import { gql } from 'apollo-boost';

const ADD_TODO = gql`
  mutation AddTodo($type: String!) {
    addTodo(type: $type) {
      id
      type
    }
  }
`;

Next is to create a functional component named AddToDo and pass our ADD_TODO mutation to the useMutation Hook:

function AddTodo() {
  let input;
  const [addTodo, { data }] = useMutation(ADD_TODO);

  return (
    <div>
      <form
        onSubmit={e => {
          e.preventDefault();
          addTodo({ variables: { type: input.value } });
          input.value = '';
        }}
      >
        <input
          ref={node => {
            input = node;
          }}
        />
        <button type="submit">Add Todo</button>
      </form>
    </div>
  );
}

Render props approach

Similar to the hooks approach, we need to import the necessary dependencies with a new mutation importation from react-apollo:

import React, { useState } from 'react';
import { useMutation } from 'react-apollo';
import { gql } from 'apollo-boost';

const ADD_TODO = gql`
  mutation AddTodo($type: String!) {
    addTodo(type: $type) {
      id
      type
    }
  }
`;

To complete, pass the created mutation as follows:

function AddTodo() {
  let input;

  return (
    <Mutation mutation={ADD_TODO}>
    <div>
      <form
        onSubmit={e => {
          e.preventDefault();
          addTodo({ variables: { type: input.value } });
          input.value = '';
        }}
      >
        <input
          ref={node => {
            input = node;
          }}
        />
        <button type="submit">Add Todo</button>
      </form>
    </div>
    </Mutation>
  );
}

Conclusion

GraphQL is a great choice when dealing with data fetching as it solves the over-fetching and under-fetching problems that come with RESTful APIs. Apollo Client makes GraphQL connection to a server easy, seamless, and efficient.

LogRocket: Full visibility into your production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket combines session replay, product analytics, and error tracking – empowering software teams to create the ideal web and mobile product experience. What does that mean for you?

Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay problems as if they happened in your own browser to quickly understand what went wrong.

No more noisy alerting. Smart error tracking lets you triage and categorize issues, then learns from this. Get notified of impactful user issues, not false positives. Less alerts, way more useful signal.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Belinda Ijeoma Frontend engineer | Technical writer | Tech enthusiast

One Reply to “Data retrieval in GraphQL with react-apollo”

Leave a Reply