Interaction with an Apollo GraphQL server from the frontend

Introduction

Apollo GraphQL allows us to build a server. That a client can query in any way they want. In this article, we will look at different ways to interact with data from the backend. We will go through the setup, query, mutation and polling or explicit fetch.

Description

We require to specify the URL to our server and instantiate a client. So, we initially make a setup like this:

  • We need the libraries apollo-boost and react-apollo to set up a React app with GraphQL.
  • The apollo-boost provides us with ApolloClient.
  • That we need to instantiate given a URL.
  • The react-apollo offers us a Higher Order Provider ApolloProvider.
  • That we need to wrap our application with.
  • First off do the essential installs:
yarn add react-apollo apollo-boost graphql
  • When 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;
  • As shown above we are first instantiating ApolloClient.
  • Then in the process providing it with a url, the location of our GraphQL server.
  • Furthermore, we are wrapping the entire application with our ApolloProvider.
  • We also set its client property with our ApolloClient instance.
  • Now we are all set to interact with our GraphQL server

Query

  • We need to do three things to be able to query an Apollo server:
  • Write our gql query
  • Utilize the Query component the react-apollo library provides us
  • Render the response

Query

  • We need to import graphql-tag and then write the GraphQL query to write our gql query, like this:
const getRates = gql`
{
  rates(currency: “USD”) {
    currency
    rate
  }
}`;
  • After that, we need to import the Query component from react-apollo.
  • As input property gives the query we just defined, like as a result:
const Data = () => (
  <Query query={getRates} >
  // render the query results
  </Query>
);
  • We are invoking a function that has an object as a parameter in the first child of our Query component.
  • The object has the below properties:
  • loading, as long as the query hasn’t been resolved this is true
  • error, if we get an error back from the query
  • data, the data result from query
  • At this time that we understand the properties and how we may use them, let’s place altogether:
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 well-familiarized how we can read data from a GraphQL server and present into to our users.

Polling

  • Sometimes we also want to fetch data at a regular interval deprived of openly navigating to a certain page or pressing an exact button for the GET request to be fired off.
  • We use this in for instance chat applications to achieve a sense of real-time.
  • We are obviously talking about polling, fetching data at a regular interval.
  • The Query factor that we learned to use has polling built-in.
  • All we need to do is to set a pollInterval property to the number of milliseconds required between fetches.
  • Let’s have a gaze at what that may look like:

Polling

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;
  • As described above we have now presented the following new concepts:
  • pollInterval, this is roughly that imagines polling interval in milliseconds, as we 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 before stopped it
  • stopPolling, is a function that permits us to stop polling any time we want.

Refetch

  • At times we end up with scenarios where we want to openly fetch the data to confirm we are looking at the latest.
  • The goal for doing so is to react to a user action rather than polling.
  • Let’s see how we may 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;
  • As shown above that we have added another argument refetch to our Query child function like this:
{(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 this:
<button onClick={() => refetch()}>Fetch</button>

Mutation

  • We need to do the following once we do a mutation against a GraphQL server:
  • invoke the correct mutation
  • use the Mutation component from react-apollo
  • The above doesn’t complete like much it isn’t.
  • So let’s begin with the first thing, our mutation query:
  • We will be using the gql helper from the graphql-tag library to create our mutation query.
  • Then we use the keyword mutation, followed by giving the mutation a name.
  • Identify its input parameter $person.
  • At the present 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
   }
}
`;
  • Subsequent up is placing the mutation query to use by working with React component Mutation.
  • The component will require two things:
  • populate the mutation property,
  • define the child of the Mutation component
  • Let’s begin with the first bit of using the Mutation component.
  • Set its mutation property, like this:
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>
  • We have taken our Mutation component into use.
  • 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 this:
(addPerson, { data, loading, error }) => (
// JSX
)
  • The function as described above is expected to return JSX.
  • We are likely to define a piece of JSX that lets us use the following:
  • addPerson(), this function that would carry out the mutation query.
  • loading, this boolean would tell us whether the 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, let’s define our JSX.
  • It is quite customary to define a Form when we want to collect data
  • Therefore, 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>

  • 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.
  • We also solve how to get data to mutation query.
  • We give the addPerson() method an object that has property variables in which assign an object to the property person.
  • That person property is the same input parameter that exists on the mutation query.
  • The other fields data, loading and error are used as conditional JSX where we select to show them if they are true.
  • That is all there is to it to invoke a mutation with some parameters
  • Show the response, whether actual data or an error.
  • Following 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;

Leave a Comment