Pablo Alejandro Berganza Campos
4 Aug 2021
•
4 min read
The first time I tried GraphQL was when I would still have considered myself as just a back-end developer. About two years ago I gave myself the opportunity to learn it thanks to NestJS's support for it and I totally felt in love with it. The fact that it's basically self-documenting and the fact that you can ask for exactly the data you want with just one request made me feel that working with a GraphQL API as a front-end developer would feel really enjoyable.
I wanted to try to make something on the front-end side with this new knowledge, to get a better feel of it. By that time I was still learning the ropes on front-end with React (last time I did front-end, jQuery was the thing to use). So, naturally, I duckduckgo'ed graphql react
and the first thing I found was Apollo. Apollo is a great tool that offers many features; you can even manage your whole application's state with it. But it did feel a bit heavy for someone who's just trying to learn how to use GraphQL, or for any small project in that sense. I will admit that it was really naive of me, but at the time I really thought: woah, so GraphQL is really only suitable for pretty big apps. Regardless, I kept on doing my experiments with Apollo. As I suspected I spent a lot of my time learning how to use Apollo, which is not bad per se, but of course it would feel daunting for anyone learning.
Sometime about last year I found urql which aims to be a lighter alternative to Apollo. I found this really appealing. And it was great. A simpler API and fewer features meant less time spent on the documentation and more time to actually build something with it. But it still felt pretty heavy for my use cases. Although right now I would probably choose urql over Apollo for a serious project, since I do feel Apollo tries to do too much for my taste.
Even though I haven't worked professionally with GraphQL yet, I've kept on using it for my personal projects. Still, I kept on feeling that the entry point for any front-end developer learning it was quite high. If you duckduckgo (or google) react graphql
your top results will be Apollo and howtographql.com. If you go to the latter, you'll see that both Apollo and urql are listed as the beginner's choice. This I feel is an artificially high entry point for a beginner.
What are the minimum requirements for making a request to a GraphQL API from the browser? Well... just the fetch API. After all, you only need to make an HTTP POST request to the GraphQL endpoint. It only needs to contain a query/mutation in the body as a string and, optionally, the variables if they're needed for the query. It doesn't need to be a POST request, and it can have an application/graphql
MIME type; but, to keep things simple, a POST request with an application/json
MIME type should always work.
fetch(`${API}/graphql`, {
method: 'post',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
query: `...`,
variables: {
...
},
})
}).then(r => r.json())
You can turn this into a more reusable function with something like this:
async function gqlFetcher(query, variables) {
const { data, errors } = await fetch(`${API}/graphql`, {
method: 'post',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ query, variables }),
}).then(r => r.json())
if (errors) throw errors
return data
}
A GraphQL server returns a 200 response even if it contains errors, so you generally only need to check if the response contains an errors
property. This is still an optimistic way of handling it, since you're not accounting for other kinds of errors such as network errors that can return 4xx or 5xx responses. For the purposes of this post we'll leave it like this.
This approach does make you lose the nice interface that Apollo and urql provide you. You can, of course, create your own hooks that provide a friendlier interface; however, I prefer to use Vercel's swr hook. This hook works for any kind of remote data fetching; it works by first returning data from the cache, then sending the fetch request, and finally returning the newly received data. It provides a nice interface for handling your data inside your component while keeping your UI, as they describe it, fast and reactive. The gqlFetcher
function we made earlier is already compatible with the useSWR
hook, so no additional work is required.
import useSWR from 'swr'
const gqlQuery = `...`
function Component() {
// gqlFetcher is the same function we defined earlier
const { data, error } = useSWR(gqlQuery, gqlFetcher)
if (error) return <div>{/*...*/}</div> // JSX with error data
if (!data) return <div>Loading...</div> // Loading component
return <div>{/*...*/}</div> // JSX with returned data
}
In order to pass multiple arguments to the fetcher
function, the swr hook allows you to pass an array as the first argument.
const gqlQuery = `...`
const gqlVariables = {
// ...
}
function Component() {
const { data, error } = useSWR([gqlQuery, gqlVariables], gqlFetcher)
// ...
}
useSWR
uses the first argument as akey
that serves to uniquely identify the request. If an array is passed,swr
shallowly compares each element and, if any of them has changed, it revalidates the request.
If you don't feel like creating your own wrapper over fetch
, you can use graphql-request. This is also a wrapper over the fetch
API for making GraphQL requests that doesn't need much work to start using it. It already handles errors nicely and is isomorphic by default (which some people might not like). The swr
GitHub page already provides an example using this.
import { request } from 'graphql-request'
const API = 'https://api.graph.cool/simple/v1/movies'
const fetcher = query => request(API, query)
function App () {
const { data, error } = useSWR(
`{
Movie(title: "Inception") {
releaseDate
actors {
name
}
}
}`,
fetcher
)
// ...
}
It feels there's an artificially high entry level for front-end developers who want to get into the GraphQL world. The fact that Apollo and urql are shown as beginner choices for learning GraphQL can make developers feel like these kinds of tools are actually required to work with a GraphQL API. This is, in fact, not the case; you can build a fully capable web application with just the fetch
API and some other small libraries for extra features. I can't think of any small project that would actually require all the features that these big libraries have to offer. To clarify: I'm not saying you shouldn't use these tools if you want to; I'm saying you don't need to feel they're required to build what you want.
Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ
108 E 16th Street, New York, NY 10003
Join over 111,000 others and get access to exclusive content, job opportunities and more!