Fetching Data from a GraphQL API

It’s common to hear GraphQL described as a REST killer. Here to slash your REST services, to end your endpoints. But today, let’s not focus on conflict. Let’s consider where GraphQL and REST share something in common: HTTP requests.

That’s right. If you know how to send HTTP requests, you already have the tools necessary to build a client application that communicates with any GraphQL API. We can get data using any method that sends an HTTP request. Let’s build a tiny client by using fetch, which will work in the browser:

const query = `
query {
Lift(id: "panorama") {
name
status
}
}
`;
const url = "https://snowtooth.moonhighway.com/";const opts = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query })
};
fetch(url, opts)
.then(res => res.json())
.then(console.log)
.catch(console.error);

We’ll send the fetch request with some options. Then we’ll convert the response to JSON. When we log the results to the console, we’ll see the following:

results

{
"data": {
"Lift": {
"name": "Panorama",
"status": "HOLD"
}
}
}

You could even display your results on an HTML page by replacing the console log with some simple DOM manipulation:

fetch(url, opts)
.then(res => res.json())
.then(
({ data }) => `
<p>
Favorite Lift: ${data.Lift.name}
Status: ${data.Lift.status}
</p>
`
)
.then(text => (document.body.innerHTML = text))
.catch(console.error);

Mutations with fetch

Whenever we want to change data, we’ll use a GraphQL mutation. Our API supports a mutation called setLiftStatus. This mutation takes in the id of the Lift you want to change and the new status for that lift. The options for LiftStatus are a GraphQL enum, a restricted list of options for a specific field. These options are OPEN, CLOSED, and HOLD. Start by defining the setLiftStatus mutation string as a variable:

const mutation = `
mutation {
setLiftStatus(id: "panorama", status: CLOSED) {
name
status
}
}
`;

Then we want to use the same GraphQL endpoint. We’ll adjust the body of the request to include the mutation:

var url = "https://snowtooth.moonhighway.com/";
var opts = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: mutation })
};

Finally, we can send the request and log the results:

fetch(url, opts)
.then(res => res.json())
.then(console.log)
.catch(console.error);

And our results will reflect that the Panorama lift status has indeed been changed by the mutation:

results

{
"data": {
"Lift": {
"name": "Panorama",
"status": "CLOSED"
}
}
}

graphql-request

There are other frameworks that can be used to send GraphQL operations to an API. One of the most minimal examples of this is graphql-request. GraphQL Request wraps fetch requests in a promise that can be used to make requests to the GraphQL server. It also handles the details of making the request and parsing the data for you. graphql-request is maintained by the team at Prisma.

To get started with graphql-request, you will need to install it:

npm install graphql-request --save

From there, you’ll import and use the module as request:

import { request } from "graphql-request";
const query = `
query {
Trail(id: "grandma") {
name
status
}
}
`;
request("https://snowtooth.moonhighway.com/graphql", query)
.then(console.log)
.catch(console.error);

The request function takes in url and query, makes the request to the server, and returns the data in one line of code. The data returned is, as expected, a JSON response of all of the users:

{
"Trail": {
"name": "Grandma",
"status": "OPEN"
}
}

Notice that the results here are a little bit different than the fetch request. Instead of returning the data under the data key, the request sent with graphql-request returns just the object. If you wanted to use this data in your app, you would access that data off of the Trail key.

ENJOY YOUR CODING!