loading...
Microsoft Azure

Consuming an Apollo GraphQL Server using React

softchris profile image Chris Noring Updated on ・7 min read

Follow me on Twitter, happy to take your suggestions on topics or improvements /Chris

This article is part of series on Graphql

This is an introduction to how we can interact with an Apollo GraphQL server from the frontend. If you are not familiar with how to create and Apollo Server, have a look at this article first Creating an Apollo Server

In this article we will go through:

  • set up, We need to specify the URL to our server and instantiate a client
  • query, There are Query components we can use to query for data
  • mutation, We can execute mutations using the Mutation component
  • polling/explicit fetch, Apollo comes with some nice functionality on polling, explicitly and fetching data

Set up

To set up a React app with GraphQL we need the libraries apollo-boost and react-apollo. apollo-boost provides us with ApolloClient that we need to instantiate given a URL. react-apollo gives us a Higher Order Provider ApolloProvider that we need to wrap our application with. First off do the necessary installs:

yarn add react-apollo apollo-boost graphql

Once we’ve installed everything we are ready to set everything up. Head over to index.js and type the following:

import React, { Component } from "react";
import ApolloClient from "apollo-boost";
import { ApolloProvider } from "react-apollo";
import Local from ./components/Local;

const localGraphQL = "http://localhost:4000/graphql";

const client = new ApolloClient({
  uri: localGraphQL
});
class App extends Component {
  render() {
    return (
      <ApolloProvider client={client}>
        <div>
          <h2>My first Apollo app </h2>
        </div>
     </ApolloProvider>
    );
  }
}
export default App;

Above we are first instantiating ApolloClient and in the process providing it with a url, the location of our GraphQL server.

Secondly, we are wrapping the entire application with our ApolloProvider and we also set its client property with our ApolloClient instance.

Now we are ready to interact with our GraphQL server.

Query

To be able to query an Apollo server we need to do three things:

  • Write our gql query
  • Utilize the Query component the react-apollo library gives us
  • Render the response

To write our gql query we need to import graphql-tag and then write the GraphQL query, like so:

const getRates = gql`
{
  rates(currency: “USD”) {
    currency
    rate
  }
}`;

Thereafter we need to import the Query component from react-apollo and as input property provide the query we just defined, like so:

const Data = () => (
  <Query query={getRates} >
  // render the query results
  </Query>
);

In the first child of our Query component we are invoking a function that has an object as a parameter. The object has the following properties:

  • loading, as long as our query hasn’t resolved this is true
  • error, if we get an error back from our query
  • data, the data result from our query

Now that we understand the properties and how we can use them, let’s put everything together:

import React from "react";
import { Query } from "react-apollo";
import gql from "graphql-tag";
const getRates = gql`
{
  products(type: "DVD") {
    name
    price
  }
}`;
const Data = () => (
  <Query query={getRates} >
  {({ loading, error, data }) => {
  if (loading) return <p>Loading…</p>;
  if (error) return <p>Error :(</p>;
  return data.products.map(({ name, price }) => (
    <div key={name}>
      <p>{`${name}: ${price}`}</p>
    </div>
   ));
  }}
</Query>
);
export default Data;

We have now learned how we can read data from a GraphQL server and present into to our user.

Polling

Not only do you want to fetch data but sometimes you also want to fetch data at a regular interval without explicitly navigating to a certain page or pressing a specific button for the GET request to be fired off. We use this in for example chat applications to achieve a sense of real-time. We are of course talking about polling, fetching data at a regular interval that we specify. The Query component that we learned to use has polling built in and all we need to do is to set a pollInterval property to the number of milliseconds we want between fetches. Let’s have a look at what that can look like:

import React from "react";
import { Query } from "react-apollo";
import gql from "graphql-tag";
const GET_DATA = gql`
{
  products {
    name
    id
  }
}
`;
const DataPull = () => (
  <Query query={GET_DATA} pollInterval={500}>
  {(loading, error, data, startPolling, stopPolling) => {
  if (loading) return null;
  if (error) return `Error!: ${error}`;
    return (
     <React.Fragment>
      {data.products.map(p => <div>{p.name}</div>)}
      <button onClick={()=> startPolling()}>Start polling</button>
      <button onClick={() => stopPolling()}>Stop polling</button>
    </React.Fragment>;
    )
}}
</Query>
);
export default DataPull;

Above we have now introduced the following new concepts:

  • pollInterval, this is something that expects polling interval in milliseconds, as you can see we set that to 500, e.g half a second
  • startPolling, this is a function in which we can start the polling anew if we have previously stopped it
  • stopPolling, this is a function that allows us to stop the polling any time we want

Refetch

Sometimes we end up with scenarios where we want to explicitly fetch the data to ensure we are looking at the latest. The reason for doing so is to react to a user action rather than polling. Let’s look at how we can use this refetch functionality:

import React from "react";
import { Query } from "react-apollo";
import gql from "graphql-tag";
const GET_DATA = gql`
{
  products {
    name
    id
  }
}
`;
const Refetch = () => (
  <Query query={GET_DATA}>
  {(loading, error, data, refetch) => {
  if (loading) return null;
  if (error) return `Error!: ${error}`;
  return (
    <React.Fragment>
      <div>
        {data.prop}
        <button onClick={() => refetch()}>Fetch</button>
      </div>
   </React.Fragment>
  )
}}
</Query>
);
export default Refetch;

Above we see that we have added another argument refetch to our Query child function like so:

{(loading, error, data, refetch) => {
}}

This refetch argument is a function that we can invoke so we can, therefore, wire it up to a button in our markup like so:

<button onClick={() => refetch()}>Fetch</button>

Mutation

When we do a mutation against a GraphQL server we need to do the following:

  • invoke the correct mutation

  • use the Mutation component from react-apollo

The above doesn’t sound like much and it isn’t. So let’s start with the first thing, our mutation query:

We will be using the gql helper from the graphql-tag library to create our mutation query. Thereafter we use the keyword mutation, followed by giving the mutation a name and specify its input parameter $person. At this point we have the following query:

const ADD_PERSON = gql`
mutation AddPerson($person: Person!) {
}
`;

Now we are ready to call the actual mutation addPerson that we defined in our GraphQL server. Your mutation query should now look like this:

const ADD_PERSON = gql`
  mutation AddPerson($person: Person!) {
    addPerson(person: $person) {
      id
    }
  }
`;

Next up is putting the mutation query to use by working with our React component Mutation. The component will need two things:

  • populate the mutation property,
  • define the child of the Mutation component, we will need to provide this with a function that as its first argument contain the mutation function that will trigger the mutation to happen and as the second argument it will take an object with the properties data, error and loading

Let’s start with the first bit of using the Mutation component and set its mutation property, like so:

import React from "react";
import { Mutation } from "react-apollo";
import gql from "graphql-tag";
const ADD_PERSON = gql`
  mutation AddPerson($person: Person!) {
    addPerson(person: $person) {
      id
    }
  }
`;
<Mutation mutation={ADD_PERSON}>
</Mutation>

Above we have taken our Mutation component in use and set the mutation property with our mutation query ADD_PERSON. Next up is defining the child of the Mutation component. As we already stated that child is a function like so:

(addPerson, { data, loading, error }) => (
// JSX
)

The function above is expected to return JSX. We are expected to define a piece of JSX that lets us use the following:

  • addPerson(), this function that will carry out the mutation query.
  • loading, this boolean will tell us whether our mutation is ongoing or not, use this value to determine whether to use a spinner or not
  • data, this is the data that comes back after your mutation query finished

Now that we understand what the function parameters are for, let’s define our JSX. It is quite customary to define a Form when we want to collect data, so let’s do that:

<form onSubmit={e => {
  e.preventDefault();
  addPerson({ variables: { person: { name: input.value } } });
  input.value = “”;
}} >
  <input ref={node => { input = node; }} />
  <button type=”submit”>Add Person</button>
  {loading &&
  <div>adding person…</div>
  }
  { data &&
  <div>response data</div>
  }
  { error &&
  <div>Error adding person…</div>
  }
</form>

As you can see above we have our Form and one input field and a button that we can press. We hook up the addPerson() method to the onSubmit() of the form. Note that we also solve how we get data to our mutation query. We give the addPerson() method an object that has a property variables in which we assign an object to the property person. That person property is the same input parameter that exist on our mutation query.

The other fields data, loading and error are used as conditional JSX where we choose to show them if they are truthy.

That’s it, that is all there is to it to invoke a mutation with some parameters and show the response, whether actual data or an error.

Below is the entire code in its entirety.

import React from "react";
import { Mutation } from "react-apollo";
import gql from "graphql-tag";
const ADD_PERSON = gql`
  mutation AddPerson($person: Person!) {
    addPerson(person: $person) {
      id
    }
  }
`;
const DataInput = () => {
  let input;
  return (
    <Mutation mutation={ADD_PERSON}>
    {(addPerson, { data, loading, error }) => (
    <div>
      <form onSubmit={e => {
        e.preventDefault();
        addPerson({ variables: { person: { name: input.value } } });
        input.value = “”;
    }} >
      <input ref={node => { input = node; }} />
      <button type=”submit”>Add Person</button>
      {loading &&
      <div>adding person…</div>
      }
      { data &&
      <div>response data</div>
      }
      { error &&
      <div>Error adding person…</div>
      }
    </form>
  </div>
)}
</Mutation>)
}
export default DataInput;

Summary

We have looked at different ways to interact with data from the backend.

  • Fetching data, if we use the Query component we can fetch data by populating its query attribute with a gql question

  • Polling for data, if we set the attribute pollInterval on the Query component we can poll against our GraphQL backend.

  • Explicit data fetch, by using the extra argument refetch, we could explicitly fetch data when we wanted it

  • Triggering mutations, we learned that we could use the Mutation component to carry out mutations

Posted on Mar 15 '19 by:

softchris profile

Chris Noring

@softchris

https://twitter.com/chris_noring Cloud Developer Advocate at Microsoft, Google Developer Expert

Microsoft Azure

Any language. Any platform.

Discussion

markdown guide