Lightweight, Modern React.js Setup for GraphQL using Vite and urql
In this tutorial, we will build a React.js application that interacts with a GraphQL endpoint. This method of project setup is modern and lightweight: it uses Hooks, ES Modules and has a small amount of dependencies. We will use Vite to create the project structure, pnpm to manage the dependencies, urql for GraphQL, and finally OneGraph as the GraphQL gateway to various APIs. Our goal is to create an application for listing GitHub repositories of a specific user.
Install pnpm
Let’s start with pnpm
, a package manager for JavaScript that is faster and more efficient than npm
or yarn
. pnpm
uses a content-addressable filesystem to store your project dependencies. This way files inside node_modules
are linked from a single place on your disk. Thus, you install each dependency only once and this dependency occupies the space on your disk only once. In other words, libraries are not copied over for each new project. This way, on top of being faster than alternatives, pnpm
provides huge disk space gains.
npm i -g pnpm
pnpm
comes with two command-line tools: pnpm
for installing dependencies and pnpx
for invoking commands (a npx
equivalent).
Create the project
Let’s use Vite to create the project structure for our React.js project. We need to initialize the project using the vite-app
generator with the React as the template. The template must be set explicitly using the --template
parameter with react
as its value. Finally, gh-explorer
is a custom name we are giving to this project.
pnpm init vite-app gh-explorer --template react
Vite is a build tool for web projects. It serves the code in development using ECMAScript Module imports. In production, vite bundles the code using Rollup. Vite is a lightweight solution that can be 100-150x times faster than alternatives such as Webpack or Parcel. This enormous speed gain is possible thanks to esbuild, a new TypeScript/JavaScript bundler written using the Go programming language.
Go inside the gh-explorer
directory and install the necessary dependencies using the pnpm install
command. Then, start the development server with pnpm dev
and head to the localhost:5000
in your browser. You should see a React.js logo along with a counter and a button.
Integrate with OneGraph
When interacting with external APIs, we need to learn the specifics for each new API we are dealing with. This is especially visible at the level of authentication. The methods of authentication are slightly different between one API and another. Even though those APIs are provided either as REST or GraphQL endpoints, it takes time and often much effort to learn how to use them. Luckly, there is OneGraph. The project provides a layer of unification for various GraphQL APIs. Using OneGraph, we can just access one endpoint and gain access to various GraphQL APIs at once. Think, a catalog of APIs. This simplifies and speeds up the development. We will use OneGraph to interact with the GitHub API.
Let’s create an application in OneGraph:
Then, we can use OneGraph's Explorer to test our GraphQL queries for GitHub before we integrate them with our React.js application. On the left side of the Explorer I have a list of all available APIs. It goes from Airtable, Box to Shopify, Stripe, Zendesk and much more. This catalog is quite impressive on its own.
Construct the GraphQL Query
Our goal is to list the repositories of a specific user. I start by selecting the GitHub API. Then, I select theuser
branch. I enter the handle of a specific user, e.g. zaiste
- in this case, it’s my own username. I go further down the GitHub API tree by selecting the repositories
branch. I want to list only the public repositories that are not forks and ordered by the number of stars. For each repository, I want to return its id
, name
and the number of stars.
Just by clicking the fields in the OneGraph Explorer I end up with the following GraphQL query:
query GitHubRepositories {
gitHub {
user(login: "zaiste") {
repositories(
first: 10
orderBy: { field: STARGAZERS, direction: DESC }
privacy: PUBLIC
isFork: false
affiliations: OWNER
) {
nodes {
id
name
stargazers(
first: 10
orderBy: {
field: STARRED_AT
direction: DESC
}
) {
totalCount
}
}
}
}
}
}
Integrate with urql
We can now execute this query from our React.js application. We will use urql, a versatile GraphQL client for React.js, Preact and Svelte. The project is lightweight and highly customizable compared to alternatives such as Apollo or Relay. Its API is simple and the library aims to be easy to use. We need to add urql
along with the graphql
as dependencies for our project.
pnpm add urql graphql
urql
provides the useQuery
hook. This function takes the GraphQL query as input, and returns the data along with errors and the fetching status as the result. We will name our component RepositoryList
. You can use the regular .jsx
extension, or .tsx
if you plan to integrate with TypeScript - it will work out-of-the-box with Vite. There is no need for additional TypeScript configuration.
export const RepositoryList = () => {
const [result] = useQuery({ query });
const { data, fetching, error } = result;
if (fetching) return <p>Loading...</p>;
if (error) return <p>Errored!</p>;
const repos = data.gitHub.user.repositories.nodes;
return (
<ul>
{repos.map(repo => (
<li key={repo.id}>{repo.name} <small>({repo.stargazers.totalCount})</small></li>
))}
</ul>
);
}
Next, in main.jsx
let’s configure our GraphQL client. We need the Provider
component along with the createClient
function from urql
, and an instance of OneGraphAuth
. For the latter, we need another dependency, i.e. onegraph-auth
.
pnpm add onegraph-auth
Let’s create an instance of OneGraphAuth
with the appId
of the application we created using the OneGraph dashboard. Then, we create a GraphQL client with the OneGraph endpoint as the url
parameter. Finally, we nest the <App/>
component inside the <Provider/>
.
import React from 'react'
import { render } from 'react-dom'
import { createClient, Provider } from 'urql';
import OneGraphAuth from 'onegraph-auth';
import './index.css'
import App from './App'
const appId = "<Your APP_ID from OneGraph goes here>";
export const auth = new OneGraphAuth({ appId });
const client = createClient({
url: 'https://serve.onegraph.com/dynamic?app_id=' + appId,
fetchOptions: () => ({ headers: auth.authHeaders() })
});
render(
<React.StrictMode>
<Provider value={client}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
)
Authenticate with OneGraph
We are almost finished. The last step is to authenticate the user against the OneGraph endpoint. It’s a unified approach for any API from the OneGraph catalog. We will use the .login
method from the onegraph-auth
with github
as the value. Once the user logs in, we will adjust the state accordingly by displaying the <RepositoryList/>
component.
import React, { useState, useEffect } from 'react'
import './App.css'
import { auth } from './main';
import { RepositoryList } from './RepositoryList';
function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false)
const login = async () => {
await auth.login('github');
const isLoggedIn = await auth.isLoggedIn('github');
setIsLoggedIn(isLoggedIn);
}
return (
<div className="App">
<header className="App-header">
<p>GitHub Projects via OneGraph</p>
<p>
{isLoggedIn ? (
<RepositoryList/>
) : (
<button style={{fontSize: 18}} onClick={() => login()}>
Login with YouTube
</button>
)}
</p>
</header>
</div>
)
}
export default App
The Result
That’s all. Here’s the final result. You may need to adjust the stylesheets for the same visual effect.
We created a React.js application using Hooks. The project has a minimal set of dependencies. It uses the modern ECMASCript Modules approach. It is efficient in disk space as it uses pnpm as the package manager. The JavaScript/TypeScript transpilation is 100-150x faster than Webpack or Parcel. We use a simple and versatile GraphQL client called urql. Finally, we access the GitHub API via OneGraph, a meta API that provides an impressive catalog of GraphQL APIs with the unified access method. The end result is lightweight and modern.
I hope you will use some of those elements in your future React.js applications. If you liked the article, follow me on Twitter for more.