In this article, we'll learn how to make GraphQL requests in the client-side of our React application with React Query, Typescript(TS) and also automatically generate TS types for our queries with GraphQL Code Generator. The following paragraphs will be explaining the essence of these technologies.
The first is Typescript(TS) which is gaining huge popularity these days and lots of developers are migrating their projects from plain Javascript to TS. Typescript being a superset of Javascript provides optional static typing making it easy to detect errors during development.
Next is GraphQL, a query language for APIs. With GraphQL, developers can get all the data needed in their application in a single request without having to under-fetch or over-fetch, unlike in REST APIs. One cool feature about GraphQL is the fact that it uses a type system(schema) to describe data queries and mutations.
Now leveraging on this feature of GraphQL schema being typed, we can turn it into Typescript types in our application frontend offering you a better developer experience since they are both typed. But, to ensure type-safety we'll be using a tool called GraphQL Codegen to help us auto-generate correct types based on our schema and also get fully typed custom React hooks for React Query.
Moving on, as developers, there are scenarios where we might not want to use a heavyweight library to fetch GraphQL API for example Apollo in our projects but would prefer a lightweight library to perform the operation. This is where React Query(a library that interacts with our API) comes into play coupled with a library called graphql-request which is pretty much like Axios or fetch but tailored to make just graphql requests.
Let's go ahead to setup the project!
Prerequisites
This article will assume you have some familiarity with using React Query and Typescript. Also, basic knowledge of GraphQL will come in handy.
Create React App
To create a new React app with the --typescript
template flag,
run;
yarn create react-app client --template typescript
If you're having issues creating a new react app due to the recent version upgrade, check out this article on how to fix it.
Then, start the development server by running
yarn start
Setup React Query
Let's install React Query library by executing the following command;
yarn add react-query
Then, open up the index.tsx
file in the project folder and set up React Query client;
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { QueryClient, QueryClientProvider } from "react-query";
const queryClient = new QueryClient();
ReactDOM.render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>,
document.getElementById('root')
);
Here we instantiated the React query client and then wrapped our top-level component within the React query client provider.
Scaffolding out the App
In the src folder of the project, create a folder called components. Right in this components
folder, create a Countries.tsx
file. The Countries
component will display lists of countries from the free public GraphQL Countries API we'll be using in this tutorial.
For the purpose of styling the component interface, Tailwind CSS will be used. Now, add the CDN link written below to the head tag of the public/index.html file.
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
In the Countries
component, add the following code;
import React from "react";
const Countries: React.FunctionComponent = () => {
return (
<div className="bg-white rounded-lg shadow-md w-80 text-center">
<div className="mt-4 p-10 text-bold">
<p>Country</p>
<p>Capital</p>
<p>Continent</p>
</div>
</div>
);
};
export default Countries;
Next, open the App.tsx
file in the project folder and update like so
import React from "react";
import Countries from "./components/Countries";
const App = () => {
return (
<>
<div className="bg-blue-100">
<header className="text-3xl text-center font-bold pt-6">Countries</header>
<div className="flex justify-center pb-2">
<div className="flex flex-col">
<div className="flex-grow">
<div className="m-4 grid grid-cols-2 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-2 gap-8 mt-8">
<Countries />
</div>
</div>
</div>
</div>
</div>
</>
);
};
export default App;
Install GraphQL-Request Library
This library will basically provide a function that accepts an endpoint. Type the following command in your terminal, so we can install graphlql-request
into our project
yarn add graphql graphql-request
The graphql
added above is a dependency for graphql-request
.
Now update the Countries
component like so
import React from "react";
import { GraphQLClient } from "graphql-request";
const graphqlClient = new GraphQLClient(
"https://countries.trevorblades.com/graphql"
);
const Countries: React.FunctionComponent = () => {
return (
<div className="bg-white rounded-lg shadow-md w-80 text-center">
<div className="mt-4 p-10 text-bold">
<p>Country</p>
<p>Capital</p>
<p>Continent</p>
</div>
</div>
);
};
export default Countries;
Here, we basically imported GraphQLClient
from graphql-request
and instantiated it.
Write Queries
Next, we need to create a countries.graphql
file in the src folder. In this file, we'll define a query to get the list of countries data we need; the country names, capital and continents.
query Countries {
countries {
name
capital
continent {
name
}
}
}
Setup GraphQL Codegen
Now, let's install graphql-code-generator
so we can have it up and running in our application. Execute the following command;
yarn add -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-react-query @graphql-codegen/typescript-operations
From the above, we installed
-
graphql-codegen
CLI so we can run ourcodegen
script. -
graphql-codegen/typescript
andgraphql-codegen/typescript-operations
plugins so we can get our generated types. -
graphql-codegen/typescript-react-query
plugin in order to generate custom React Query hooks.
Let's also create a codegen.yml
file where we'll configure how we want our code to be generated.
overwrite: true
schema: "https://countries.trevorblades.com/graphql"
documents: "src/**/*.graphql"
generates:
src/generated/index.ts:
plugins:
- "typescript"
- "typescript-operations"
- typescript-react-query
config:
fetcher: graphql-request
-
schema
is the URL for the free public GraphQL API we are using in this tutorial. -
documents
tellsgraphql-codegen
to locategraphql
files, in this case thecountries.graphql
file. -
generates
defines the file path where the types will be generated once we run a definedgraphql-codegen
script. -
plugins
represents the plugins we installed earlier. -
fetcher
configuration letsgraphql-codegen
know we are usinggraphql-request
to fetch our data.
Then, let's add our graphql-codegen
script into our package.json file like so;
Next, let's run our script so we can have generated custom types added automatically to our project src
as a folder titled generated
;
yarn generate
Display the Data
In the Countries
componet, let's update our code as shown below;
import React from "react";
import { GraphQLClient } from "graphql-request";
import { CountriesQuery, useCountriesQuery } from "../generated";
const graphqlClient = new GraphQLClient(
"https://countries.trevorblades.com/graphql"
);
const Countries: React.FunctionComponent = () => {
const { data, isLoading, error } = useCountriesQuery<CountriesQuery, Error>(
graphqlClient,
{}
);
if (isLoading) {
return <div className="box">Loading...</div>;
}
if (error) {
return <div>Error!</div>;
}
return (
<>
{data?.countries?.map((country) => {
return (
<div className="bg-white rounded-lg shadow-md w-80 text-center">
<div className="mt-4 p-10 text-bold">
<p>Country: {country.name}</p>
<p>Capital: {country.capital}</p>
<p>Continent: {country.continent.name}</p>
</div>
</div>
);
})}
</>
);
};
export default Countries;
From the code above, to interact with the Countries API we are importing the fully typed custom hooks generated by graphql-codegen
in place of the usual useQuery
hook from React Query library. Then, we looped through the response data to display the lists of countries, capital and continents.
Now you have it!. The final application should look like this;
You can access the project source code in this Github repo. Thanks for reading!
Conclusion
In this article, we were able to make GraphQL API request successfully in our client-side application. By also incorporating the power of the GraphQL codegen library, we were able to generate fully typed custom React Query hooks for our application from the GraphQL schema.
Top comments (1)
Is there a way to not constantly having to pass the graphl client into the generated react-query hook? Seems very tedious for me.
How about JWT auth? Any way to modify the graphl client?