GraphQL Client Libraries
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
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:
- End Pointer Patrick Lewis documented some of his experiences using GraphQL with Ruby here and here.
- Apollo Android
- graphql-php
Comments