#What is GraphQL
GraphQL is a query language and a runtime to efficiently write and manage backend APIs. It is designed to reduce overheads and frontend couplings that come with REST APIs, efficiently manage data from multiple sources and provide a great developer experience. It was developed by Facebook in 2012 to use internally and made public in 2015. It allows querying, mutating data, and also publishing/subscribing to real-time events. Due to numerous advantages, it has become a great alternative to REST APIs, you can read about the precise differences here. Along with us a lot of other reputed software firms also use it in production.
#Ways to fetch data from a GraphQL Server
When we want to call a backend Graphql API server to query or mutate some data there are many clients that we can use from the frontend. It really depends on the use case and the scope of the project. In this article, we will learn by examples how to query data from the frontend using different clients. We will start from the bottom with most basic methods like a simple fetch
API call to all the way towards using full-fledged clients like apollo-client
Server Side Setup
For this example, first we will need a server side API that the clients can invoke. We will use the Hygraph platform as it will give us a ready to use GraphQL API within a few minutes. If you are new to Hygraph, please refer to this 5 minute guide to understand the fundamentals. You can create a Hygraph project, create your schema. We can do a small schema setup wherein we have one model named NextUser
and another model named Post
. The relationship is one user can have multiple posts
.
Once you have the project and schema defined, your API is ready to use. Querying user details on the Hygraph API playground is quite easy, once your schema is in place, write your query/mutation and give the variables, then hit the play button, it will give you the results.
Here we are sending a query to get details of a user, we pass email as a variable to this query. You can do a similar setup on Hygraph within few minutes, and in case you already have any other GraphQL API server running you’re good to go. On the frontend side, we will be using a Next.js
application.
Understanding of React and Next.js is a prerequisite for this article. In case you are unfamiliar with these, you can get started checkout these articles for understanding React and Next.js better.
Recommended reading
The code snippets ahead will contain the core parts, in case you’re stuck somewhere, please find the final working Next.js app with all different clients here. If you want to clone and work with this repository, please create a .env.local
file, then add HYGRAPH_URL
and HYGRAPH_PERMANENTAUTH_TOKEN
environment variables for your setup.
.env.local
NEXT_PUBLIC_HYGRAPH_URL=add-your-hygraph-api-urlNEXT_PUBLIC_HYGRAPH_PERMANENTAUTH_TOKEN=add-your-hygraph-token
If you’re building a small application, or if your application has only few Graphql API calls then you might not need a dedicated Graphql client, and using an existing package like fetch
/ axios
/ request
to make those API calls might do the job. Okay, before getting started with code for different clients let us set up the constants file, we will define our Hygraph server connection details and one GraphQL query that we will send to the server using different clients.
lib/constants.js
export const HYGRAPH_URL = process.env.NEXT_PUBLIC_HYGRAPH_URL;export const HYGRAPH_PERMANENTAUTH_TOKEN = process.env.NEXT_PUBLIC_HYGRAPH_PERMANENTAUTH_TOKEN;export const GRAPHQL_QUERY = `query getNextUserByEmail($email:String!){nextUser(where:{email:$email}){firstnamelastnameposts{title}}}`;
Fetch
At its very base an API call to a GraphQL server is still an HTTP network call, this means that we can use Curl / Fetch with the correct parameters and payload to make the API call.
Here is an API request using JavaScript’s native fetch
. We have used tailwind for styling feel free to use any UI/CSS framework. (Full React component here) .
import { React, useState } from 'react';import { HYGRAPH_URL, HYGRAPH_PERMANENTAUTH_TOKEN, GRAPHQL_QUERY } from '../lib/constants';import { UserDetail } from '../components/UserDetail';export default function Fetch() {const [email, setEmail] = useState('');const [userDetails, setUserDetails] = useState({});const [isLoading, setIsLoading] = useState(false);const getUserDetailByFetchAPICall = async () => {try {if (!email) {return;}setIsLoading(true);const headers = {'content-type': 'application/json',Authorization: `Bearer ${HYGRAPH_PERMANENTAUTH_TOKEN}`,};const requestBody = {query: GRAPHQL_QUERY,variables: { email },};const options = {method: 'POST',headers,body: JSON.stringify(requestBody),};const response = await (await fetch(HYGRAPH_URL, options)).json();console.log('RESPONSE FROM FETCH REQUEST', response?.data);setUserDetails(response?.data?.nextUser ?? {});} catch (err) {console.log('ERROR DURING FETCH REQUEST', err);} finally {setIsLoading(false);}};return (<div className="flex w-full h-3/4"><div className="flex flex-col justify-evenly rounded-lg shadow-xl w-1/2 p-4 m-4 bg-gray-900"><h2 className="text-center text-white font-medium text-2xl mb-4 self-start ">FETCH CALL</h2><inputclassName="border-2 outline-none p-2 rounded-md"type="email"placeholder="Email"value={email}onChange={(e) => {setEmail(e.target.value);}}/><buttonclassName="flex justify-centerp-2 rounded-mdbg-gray-800 text-white hover:bg-gray-700 w-1/2 self-center"onClick={() => getUserDetailByFetchAPICall()}>{isLoading ? (<div className="mr-2 w-5 h-5 border-l-2 rounded-full animate-spin" />) : null}<span>FETCH</span></button></div><UserDetail user={userDetails} /></div>);}
Here we have used the fetch method to our Hygraph server which is a POST call, the graphql query/mutation and respective variables are passed as a part of the request body. And for authentication, we have passed a standard Authorization header with a bearer token.
Axios
The Axios implementation is quite similar to fetch, Axios is a bit more high level and developer friendly library and many code bases might already be using Axios. Here’s what an axios call would look like. (Full component here)
import { React, useState } from 'react';import { HYGRAPH_URL, HYGRAPH_PERMANENTAUTH_TOKEN, GRAPHQL_QUERY } from '../lib/constants';import { UserDetail } from '../components/UserDetail';import axios from 'axios';export default function Fetch() {const [email, setEmail] = useState('');const [userDetails, setUserDetails] = useState({});const [isLoading, setIsLoading] = useState(false);const getUserDetailByAxiosAPICall = async () => {try {if (!email) {return;}setIsLoading(true);const headers = {'content-type': 'application/json','Authorization': `Bearer ${HYGRAPH_PERMANENTAUTH_TOKEN}`};const requestBody = {query: GRAPHQL_QUERY,variables: { email }};const options = {method: 'POST',url: HYGRAPH_URL,headers,data: requestBody};const response = await axios(options);console.log('RESPONSE FROM AXIOS REQUEST', response.data);setUserDetails(response?.data?.data?.nextUser ?? {});}catch (err) {console.log('ERROR DURING AXIOS REQUEST', err);}finally {setIsLoading(false);}};return (// ... JSX Markup);}
With libraries like fetch or axios you will manually have to manage loading states for all the queries and mutations, write separate code for error handling as well. This might become an overhead when the number of requests scale. Also advanced features like client side caching, graphql subscriptions based on websocket protocols, refetching queries, cannot be used in a straight-forward manner.
Apollo Client
Apollo client is a robust, production-ready, and mature client for graphql on the web. It is the most popular graphql client and has support for major frontend frameworks. It enables us to use powerful features like polling & refetching data, simplifies managing and configuring client-side cache, helps to use graphql fragments, and also supports subscriptions. If you are building a full-blown enterprise application that relies heavily on GraphQL, you might want to consider using the Apollo client.
Let’s see how to configure the Apollo client in a Next.js app. First, make a file that initializes and exports the Apollo client.
lib/apolloClient.js
import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client';import { HYGRAPH_URL, HYGRAPH_PERMANENTAUTH_TOKEN } from '../lib/constants';import { setContext } from '@apollo/client/link/context';const httpLink = createHttpLink({uri: HYGRAPH_URL,});const authLink = setContext((_, { headers }) => {return {headers: {...headers,authorization: `Bearer ${HYGRAPH_PERMANENTAUTH_TOKEN}`}};});const client = new ApolloClient({link: authLink.concat(httpLink),cache: new InMemoryCache()});export default client;
Next.js is a hybrid framework, so if you are using static or server rendered pages you can directly import and use this client right away. For client side rendering we can provide the client via ApolloProvider.
Import this client in your _app.js
and then use ApolloProvider
to provide this client to your components down the tree.
pages/_app.js
import React from 'react';import Layout from '../components/Layout';import '../styles/globals.css';import client from '../lib/apolloClient';import { ApolloProvider } from '@apollo/client';export default function MyApp({ Component, pageProps }) {return (<Layout><ApolloProvider client={client}><Component {...pageProps} /></ApolloProvider></Layout>);}
Now, simply use hooks provided by apolloClient like useQuery
, useLazyQuery
, etc in your component something like this. (Full component here)
import { React, useState } from 'react';import { UserDetail } from '../components/UserDetail';import { gql, useLazyQuery } from '@apollo/client';import { GRAPHQL_QUERY } from '../lib/constants';export default function ApolloClient() {const query = gql(GRAPHQL_QUERY);const [email, setEmail] = useState('');const [getUserDetailByApolloClientAPICall, { loading, error, data }] = useLazyQuery(query, { variables: { email } });if (error) return <div> Error ! </div>;return (// ... JSX Markup);}
We don’t have to manage the loading, error states manually for all queries, also there is a common client that can be used by any component unlike axios / fetch where all API calls need to send the payload to the url with the authentication header. The advanced features that Apollo Client supports are beyond the scope of this article but they are worth looking into.
GraphQL Request
GraphQL Request is another lightweight graphql client with good features and ease of use. It can be considered as a GraphQL client meant to provide ease of use and can be put above a normal fetch or axios API call, but it does not have as many advanced features like cache management as the apollo client, so functionality wise it lies somewhere between the axios and apollo client.
Here’s how to use it.
import { React, useState } from 'react';import { HYGRAPH_URL, HYGRAPH_PERMANENTAUTH_TOKEN, GRAPHQL_QUERY } from '../lib/constants';import { GraphQLClient, gql } from 'graphql-request';import { UserDetail } from '../components/UserDetail';const client = new GraphQLClient(HYGRAPH_URL, {headers: {Authorization: `Bearer ${HYGRAPH_PERMANENTAUTH_TOKEN}`,},});const query = gql`${GRAPHQL_QUERY}`;export default function GraphQLRequest() {const [email, setEmail] = useState('');const [userDetails, setUserDetails] = useState({});const [isLoading, setIsLoading] = useState(false);const getUserDetailByGraphQLRequestAPICall = async () => {try {setIsLoading(true);const variables = { email };const response = await client.request(query, variables);console.log('RESPONSE FROM GRAPHQL-REQUEST API CALL', response);if (response?.nextUser) {setUserDetails(response.nextUser);}}catch (err) {console.log('ERROR FROM GRAPHQL-REQUEST API CALL', err);}finally {setIsLoading(false);}};return (// ... JSX Markup);}
#Conclusion
In this article, we had an introduction to GraphQL and learned how to setup a Hygraph GraphQL API within minutes, then we went through different client side options like Fetch, Axios, Apollo Client, and GraphQL Request to make GraphQL requests to our Hygraph API server with code examples. You can also take a look here to check out more GraphQL clients and if you are new to graphql we recommend checking out these awesome tools that are quite popular in the graphql community.