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:
- Support for modern React Hooks
- Compatibility
- Strong community support
- 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.
Get setup with LogRocket's modern React error tracking in minutes:
- Visit https://logrocket.com/signup/ to get an app ID.
- Install LogRocket via NPM or script tag.
LogRocket.init()
must be called client-side, not server-side. - (Optional) Install plugins for deeper integrations with your stack:
- Redux middleware
- ngrx middleware
- Vuex plugin
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
useQuery is not present in react-apollo