Our Blog

Ongoing observations by End Point people

GraphQL Client Libraries

By Zed Jensen
July 19, 2019

three brown wooden boat on blue lake water taken at daytime
Photo by Pietro De Grandi on Unsplash

Last week I covered some of the more popular GraphQL libraries for servers. This post will cover some options for GraphQL clients. Similarly to last week, the examples in this post won’t necessarily be everything you’d need to get a server running; instead, they’re designed to give you an idea of what it might be like to use each library. If you’re unfamiliar with GraphQL, please check out my earlier post GraphQL — An Alternative to REST for more information.

Apollo Client

This is the client with which I’m the most familiar—I’ve used its React version, so I’ll show an example of how you’d use it with a React component. However, there are also versions available for Angular, Vue.js, native iOS and Android, and Scala.js.

First we need to set up our Apollo client so it knows where our server is:

import ApolloClient from "apollo-boost";

const client = new ApolloClient({
  uri: "https://your-server.com"
});

Next, you need to make sure the root component of your application is wrapped in an ApolloProvider:

class App extends Component {
  render() {
    return (
      <ApolloProvider client={client}>
        <RestOfYourApp />
      </ApolloProvider>
    );
  }
}

Everything within the ApolloProvider has access to your GraphQL API.

To give a component access to query results in a React component, you wrap it in a component like so:

class MyQueryComponent extends React.Component {
  render() {
    const QUERY = gql`
      query ($id: String!) {
        post(id: $id) {
          body
        }
      }
    `;

    return (
      <Query
        query={QUERY}
        variables={{ id: 'id here' }}
      >
        {({ data, error, loading }) => {
          if (loading) {
            return <p>Loading</p>;
          }

          if (error) {
            return <p>Error: {error}</p>;
          }

          return (
            <div>
              <h3>Here's the body of a blog post, fetched from the server:</h3>
              <p>{data.post.body}</p>
            </div>
          );
        }}
      </Query>
    );
  }
}

The Query component also lets you provide callback functions like onComplete, which runs on a successful response from the server.

Mutations work in much the same way. The main difference is that the child function of the Mutation component takes as its first argument a function that runs the mutation, which you can call whenever you like (in this example, when the user clicks a button).

class MyMutationComponent extends React.Component {
  render() {
    const MUTATION = gql`
      mutation ($id: String!, $body: String!) {
        updatePost(id: $id, body: $body)
      }
    `;

    return (
      <Mutation query={MUTATION}>
        {updatePost => (
          <Button
            onClick={() => {
              updatePost({
                variables: {
                  id: 'id here',
                  body: 'new body here'
                }
              });
            }}
          />
        )}
      </Mutation>
    );
  }
}

Apollo GraphQL works well with React, at the small cost of adding a couple levels of indentation.

Relay

Relay is another GraphQL library for JavaScript. It’s built specifically for React applications and has a similar format to Apollo. I’m not as familiar with it, but it has a similar setup process to that of react-apollo. Here are the same examples that I used for Apollo but with Relay instead:

import {
  Environment,
  Network,
  RecordSource,
  Store,
} from 'relay-runtime';

function fetchQuery(
  operation,
  variables,
) {
  return fetch('/graphql', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      query: operation.text,
      variables,
    }),
  }).then(response => {
    return response.json();
  });
}

const environment = new Environment({
  network: Network.create(fetchQuery),
  store: new Store(new RecordSource()),  
});

Here is one of the first differences from Apollo: Relay doesn’t have a Provider component that you put at the root of the app. Instead, you provide this environment variable to components that need access to your GraphQL API, as in the following example (corresponding to the earlier Apollo component with the same name) of a component displaying the result of a query:

import { graphql, QueryRenderer } from 'react-relay';

const environment = /* defined or imported above... */;

class MyQueryComponent extends React.Component {
  render() {
    return (
      <QueryRenderer
        environment={environment}
        query={graphql`
          query ($id: String!) {
            post(id: $id) {
              body
            }
          }
        `}
        variables={{ userID: 'id here' }}
        render={({error, props}) => {
          if (error) {
            return <div>Error!</div>;
          }
          if (!props) {
            return <div>Loading...</div>;
          }
          return (
            <div>
              <h3>Here's the body of a blog post, fetched from the server:</h3>
              <p>{data.post.body}</p>
            </div>
          );
        }}
      />
    );
  }
}

There’s one more step to do before you can use these queries, though—before you’re able to run the app, you have to compile your queries with yarn relay.

I haven’t used Relay much, but it seems like a similar option to Apollo, and is also developed and used by Facebook.

GQL (Python)

GQL is an alternative option for Python. However, it works pretty differently on the developer’s side. From their own README:

gql works by parsing query files (**/*.graphql by default) into their own Python module where a class, named after the operation defined in the file, allows you to make that query and get a typed response.

Before doing anything else, you do have to initialize your project against your GraphQL server with gql.init. Setup after that is very simple; for our earlier query example, we’d have a file getpost.graphql with our query like this:

query GetPost($id: String!) {
  post(id: $id) {
    body
  }
}

Run gql run and the generated Python class would look something like this:

# AUTOGENERATED file. Do not Change!
from typing import Any, Callable, Mapping, List
from enum import Enum
from dataclasses import dataclass
from dataclasses_json import dataclass_json
from gql.clients import Client, AsyncIOClient


@dataclass_json
@dataclass
class GetPost:
    @dataclass_json
    @dataclass
    class GetPostData:
        @dataclass_json
        @dataclass
        class Post:
            body: str
        post: Post = None

    data: GetPostData = None
    errors: Any = None

    @classmethod
    def execute(cls, id: str, on_before_callback: Callable[[Mapping[str, str], Mapping[str, str]], None] = None) -> GetPost:
        ...

    @classmethod
    async def execute_async(cls, id: str, on_before_callback: Callable[[Mapping[str, str], Mapping[str, str]], None] = None) -> GetPost:
        ...

So, to run a query, you just have to import the class and run execute:

from .get_post import GetPost

result = GetPost.execute('meaning_of_life')
post = result.data.post

GQL seems pretty straightforward, and is a little easier to set up and understand than some of the other examples we’ve seen. As you might have noticed from the Python class generated earlier, it also provides a way to execute queries asynchronously.

Conclusion

That covers a few of the most popular libraries for GraphQL! Hopefully these posts have been helpful in bringing to light options for implementing GraphQL in your project. If there’s one you feel I should add, please leave a comment. Following are a few relevant links for languages I didn’t cover:

graphql


Comments

Popular Tags


Archive


Search our blog