There are many advantages to using GraphQL as a datasource for frontend development, compared to REST APIs. We developers in example need to write a lot of imperative code to retrieve data to display in our applications and handle state. With GraphQL you cannot only decrease the amount of code needed around data fetching and state-management you'll also get increased flexibility, better performance and most of all an improved developer experience. In this workshop you'll learn how to handle GraphQL in your frontend React application, compare different clients and can even auto generate code based on GraphQL!
Clone this repository (or fork it) and install all dependencies by running:
npm i
# or
yarn
After the installation is completed, run the development server:
npm run dev
# or
yarn dev
Open http://localhost:3000 with your browser to see the result. Mocked data from and DEV.to is being pulled into the application using GraphQL and StepZen.
You can start editing the page by modifying pages/index.js
. The page auto-updates as you edit the file.
This application uses a mocked GraphQL API for Github and DEV.to, you can explore it in StepZen GraphQL Studio or using GraphiQL. From StepZen GraphQL Studio, you can find the GraphQL API endpoint that leads to GraphiQL in the top-right of your screen (or here).
Run the following query that will combine information from a (mocked) Github user and its repositories and articles from DEV.to:
{
github_user(login: "githubteacher") {
bio
repositories {
edges {
node {
id
name
}
}
}
}
devto_getArticles(username: "cerchie") {
title
url
}
}
Can you alter the query to get the description
, stargazerCount
(number of stars), and the updatedAt
fields from Github? This query needs to be added to the function that fetches the data from the GraphQL API in pages.index.js
.
Show solution
The new query becomes:
{
github_user(login: "githubteacher") {
bio
repositories(first: 5) {
edges {
node {
id
name
description
stargazerCount
updatedAt
}
}
}
}
devto_getArticles(username: "cerchie") {
title
url
}
}
This must be added to the fetch
function on line 81. Save your code and return to the application on http://localhost:3000 to see more information being displayed for the (mocked) repositories.
The query you've used in the previous exercise has a query parameter, which can be better handled from a named query. Next to helping you to handle query variables, named queries are important for your GraphQL API and Client later, as they are often used for caching purposes.
Go to StepZen GraphQL Studio or GraphiQL and change the query to a named one that takes the login
query parameter. Also, use this named query in the fetch
function in pages/index.js
. How would you handle the variable for the query parameter?
Hint: It doesn't matter how you name your query.
Show solution
The named query must be added to the fetch
function around line 81. The query and the variable for the query parameter are added as follows:
So far we've been using mocked data to get the Github and DEV.to information, but let's use some real data. More importantly, your own Github data (and DEV.to if you have an account)! From StepZen GraphQL Studio you can select to use mocked data, or actual data for which you need to have a Github Personal Access Token. Create a Github personal access token here.
After creating a Github Personal Access Token go to StepZen GraphQL Studio and deselect the "mocked" toggle. The GraphQL schema for this endpoint will change and a new endpoint will be generated. You can find the new endpoint in the top-right of the screen (or here).
Try getting your own Github repositories by adding your Personal Access Token for the github_token
query parameter in GraphiQL, and replace the GraphQL API endpoint and query in pages/index.js
with new ones.
Show solution
The GraphQL API endpoint needs to be replaced with the new one, which has a different GraphQL schema that is requesting the data from the actual Github API. Also, it takes a value for github_token
to get your data from Github. (Note: no 'Bearer' prefix required)
Let's start using a JavaScript / GraphQL fetching library to get our data now, which you need to install from npm:
npm i graphql graphql-request
# or
yarn add graphql graphql-request
After installing these, you can replace the fetch
method with the request
method. This should look something like this:
import { request, gql } from 'graphql-request';
const query = gql`
{
Movie(title: "Inception") {
releaseDate
actors {
name
}
}
}
`;
const result = await request('YOUR_GRAPHQL_ENDPOINT', query, {
/* variables */
}).then((data) => (data));
You may need to adjust how props
are returned since there will be no data wrapper:
return {
props: {
...result
},
};
Replace the GraphQL API endpoint, query and variables with the correct values!
Suppose you want to do multiple queries from your application, like to get a specific repository when you click a link. You don't want to duplicate the configuration for your GraphQL request in every method. Instead, you can create a client
instance that can be used for every query you want to run. Create a new file pages.client.js
in which you define this instance https://github.com/prisma-labs/graphql-request#usage.
Refactor the request
method in pages/index.js
to use the client instance. Also, open the file repository/[...params].js
. Import the client and use a request
method to get the data for this page. The page should display a specific repository based on the params in the URL, e.g. http:localhost:3000/repository/stepzen-dev/examples
should show the repository from (https://github.com/stepzen-dev/examples)[https://github.com/stepzen-dev/examples].
Hint: The a
element to visit a repository detail page should look like <a key={id} href={
repository/${owner.login}/${name}} className={styles.card}>
. Where would you get this information from?
Show solution
In client.js
you should have the following. Include an Authentication
header with your StepZen API Key if you're not using the StepZen GraphQL Studio endpoint, but have deployed the schema on your own account.
In pages/index.js
you need to import client
from the file client.js
, and use the request
method from this client instance to query the GraphQL API.
Also, change the query
so it will get the owner
field.
Finally, in repository/[...params].js
you should import the client instance so the repository data will be requested from the GraphQL API.
When you're reusing fields in GraphQL queries, you can make use of a Fragment. The queries used in pages/index.js
and pages/repository/[...param].js
both need fields from a Github repository. How would you write this fragment?
Show solution
const query = gql`
fragment RepositoryFields on Github_Repository {
id
name
description
stargazerCount
updatedAt
}
query GetGithubRepository(
$name: String!
$owner: String!
$github_token: Secret!
) {
github_repository(name: $name, owner: $owner, github_token: $github_token) {
...RepositoryFields
}
}
`;
Our GraphQL API supports cursor-based pagination, which we can make use of in the application. If you'd look at the following query:
query MyQuery(
$login: String!
$username: String!
$github_token: Secret!
$first: Int!
$after: String!
) {
github_user(login: $login, github_token: $github_token) {
bio
repositories(first: $first, after: $after) {
pageInfo {
endCursor
hasNextPage
}
edges {
node {
id
name
description
stargazerCount
updatedAt
}
}
}
}
devto_getArticles(username: $username) {
title
url
}
}
The query parameters for first
and after
are used for pagination. With first
you define the amount of results, while after
is the cursor of the last result on the previous page. Think of cursor
as offset
, which you might know from other pagination methods. To dynamically get the value for after
you should use the value from the endCursor
field in pageInfo
. Also, hasNextPage
lets you know if there is a next page based on first
and endCursor
values.
Implement pagination for the repositories in pages/index.js
. Use a small value for first
if you don't have many repositories linked to your Github account.
Let's convert our files to TypeScript, so we can autogenerate the code to do our requests to the GraphQL API. First, install GraphQL Codegen and it's dependencies:
npm i @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-graphql-request
# or
yarn add @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-graphql-request
Second, rename pages/index.js
to pages/index.tsx
. And install the following dependencies:
npm i --save-dev typescript @types/react@17
# or
yarn add --dev typescript @types/react@17
Create a new file called codegen.yml
with the following contents:
overwrite: true
schema: 'https://graphql07.stepzen.net/api/0777b07452dfe5d76ce46a4fecb3918d/__graphql'
documents: '**/*.graphql'
generates:
graphql.ts:
plugins:
- 'typescript'
- 'typescript-operations'
- 'typescript-graphql-request'
Then create a file called queries.graphql
and add all the queries from pages/index.js
and pages/repository/[...param].js
into it.
Finally, add the generate
script to your package.json
file:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"generate": "graphql-codegen --config codegen.yml"
}
You can run npm run generate
or yarn generate
and a new file called graphql.ts
is generated. This has types for your GraphQL schema from the URL from StepZen GraphQL Studio (or your own GraphQL API endpoint) and for the queries as defined in queries.graphql
. Use the generated code for GraphQL Request in the application!
You can use React Query to add caching, prefetching, refetching, and tons of other features to your GraphQL application. See here for more information on React Query for GraphQL, as we're doing Server-side requests in this application make sure to follow these docs while setting up.
Show solution
Install react-query
from npm:
npm i react-query
# or
yarn add react-query
And make the following changes:
To learn more about Next.js, take a look at the following resources:
- Next.js Documentation - learn about Next.js features and API.
- Getting Started with StepZen - quickstarts for StepZen.
You can check out the StepZen GitHub repository - your feedback and contributions are welcome!