GraphQL lets a frontend developer quickly mock sample data, and switch to real data when the backend is done. In this tutorial I show how to mock fields, queries and mutations on client side
Nowadays, distributed architectures of software have become more popular, and along with the trend, software teams use the API-first approach to building products.
On the other hand, architects and developers decide to use the GraphQL API instead of REST more and more (but REST APIs are still good for sure)
I will not cite the well-known advantages and disadvantages of GraphQL here, but I want to stand the one that is not well-known but is quite important for developers:
One of the most significant advantages of using GraphQL is that a frontend developer can quickly mock sample data, and switch to real data when the backend is done.
What exactly is mock-up data?
Suppose some functionality needs data from the backend or somehow needs to communicate with the API, and this data is not available, or the API hasn’t been done yet. In that case, the Front-end developer needs to mock up some sample data. Take a look at the examples below:
1. Displaying additional information about a product
A development team is working on displaying additional information about a product on a product page. The data are called “Key features” and consist of an image, a name, and a description. This data will come from the backend. The backend team hasn’t started working on this functionality yet, so the Frontend developer decides to mock up this data and display this mockup on the front end. When the backend is done, the mockup data will be replaced with real data.
2. Sending a message to a seller
This functionality lets customers send a message to a seller. A customer fills out the form. He enters his name, surname, e-mail address, and message. Additionally, they must accept consent to the processing of personal data. The frontend developer has already built the form and validation and is at the stage of sending the form to the backend. The backend must pick up the form and return a success or error message, and this message will be displayed to the user. The backend part is not ready yet, so the Frontend developer needs to mock this interaction with the backend.
In summary, when some data like fields or even data collections have not been done yet in backend implementation, developers use fake values (mock data) and replace them with real data when the backend is ready.
In this article, I show how to mock:
-
single fields
-
queries
-
mutation
In the end, I will show you how to easily replace mock data with real backend data.
With this knowledge, you will be able to work on your front end more efficiently, even when the back end is lagging far behind.
Prerequisites
Computer with a text editor, NodeJS, internet connection, basic JavaScript, React, and GraphQL skills.
Create react app
I use create-react-app to scaffold a new project:
Install Apollo Client
Next, I use the command line to install the apollo client:
Apollo client allows connecting with GraphQL server and performing GraphQL operations like queries and mutations thanks to custom React hooks like useQuery or useMutation.
Initialize Apollo client
Once the client is installed, I can connect my front end with GraphQL API. This time I am going to use publically available SpaceX GraphQL API.
First, I import Apolo Client, InMemoryCache, and ApolloProvider from @apollo/client.
Second, I initialize the client:
That is the minimal config needed to make Apollo Client working - URL to API and in-memory cache initialized.
Third, I wrap the App component by ApolloProvider:
ApolloProvided takes one argument: a client that we have already initialized. Once I wrap the App component with ApolloProvider, I can use the client in the App component and every child of the app component.
How to mockup single fields
In this example, I show you how to fetch existing fields from the API and how to add a field that doesn’t exist in the response.
Create the missions component
In the beginning, I create the Missions component that will be responsible for displaying missions.
Create components \ missions \ Missions.jsx file:
Create components \ missions \ index.js file:
Create components \ index.js file:
Import Missions component in the App.js:
Render component:
Add styles to App.css:
The component in the browser should look like this:
The query for the data
I want to fetch missions from the graphql server. To do so, I need to define a query.
I add file components \ missions\ missions.gql.js:
I import the query and useQuery hook in components \ Missions \ missions.jsx:
I use the useQuery hookto fetch graphql data:
I add a little logic to handle loading and errors state:
Finally, I render data returned from API:
The complete code of the component looks like this:
You should see rendered data in the browser:
Extend GraphQL schema on the client side
Here, the main topic of the article begins! The Missions component renders some data about missions on the front like description, name, web links and so on:
I want to mock one single field, which is a sponsors field, and it is an array of strings. To do so, I create the graphql-type-defs.js file in the root of the project with the following content:
That schema definition extends the Mission type and ads sponsors field to it.
Now I import my type definition in the index.js file:
And pass it to the ApolloClient constructor:
Define a read function with mock data
The Next step is to define a custom read function to produce mock data for us.
Before I do that, I install FakerJS. it’s a library (fake data generator) that helps produce fake and random data.
Then, I pass the configuration with object types policies to the InMemoryCache constructor:
That code defines the read() function for the sponsors’ field of the Mission type. The read() function returns fake objects. In this case, it returns a new array of from one to five elements. Elements in that array are random words.
Query with the @client directive and display data
To fetch the mock field, I need to add it to the query. To make it work, I need to use the @client directive. Take a look at the updated missions query:
Finally, I can render the sponsors field on the front end. I add this code to the render function of the missions component:
Results in the browser:
How to mockup an entire query
Mocking single fields is so useful. Moreover, sometimes devs want to mock a query or mutation that doesn’t exist in the backend. Let’s start by mocking a query.
Add a new query to the schema
Let’s add the publications query that returns an array of publications (name of the publication and URL).
I extend the graphql-type-defs.js by adding new types:
Define resolver
Next, I need to define a resolver that will produce fake data for the publications query.
I create a graphql-resolvers.js file:
I defined the publications function that returns a new array of fake publications.
Register resolver
To register the resolver, you need to pass it to the ApolloClient constructor:
Use mocked query in the app
Let’s create the publications component that displays mocked data.
components \ publications \ Publications.jsx
(1.) I imported the publications query in this place, and here (2.) I used in it the useQuery hook.
As you can see from the component and useQuery hook perspective, it’s not important if the quarry that is used is fake or real. It’s transparent and works in the same way.
components \ publications \ publications.gql.js:
Directive @client allows defining not only fields like in the previous example but also queries and mutations.
components \ publications \ index.js:
components \ index.js:
Add the publication component in the App.js:
Results in the browser:
Ho to mock a graphql mutation
The last example I want to show is how to mock a graphql mutation. Let’s implement a simple form that allows users to submit a new publication. The form has two inputs: the title of the publication and its URL.
Add the PublicationForm component
Create a file components \ PublicationForm \ PublicationForm.jsx
So there are two fields in the form and the submit button. When a user clicks submit, the submitForm function is called. For now, it only logs to the console.
Create a file components \ publicationForm \ index.js
Re-export component in components/index.js:
Add the component to the render function of the app component:
Add the mutation to the schema
Let’s define a new mutation in our graphql schema:
The final graphql-type-defs looks like this:
Define a resolver for the mutation
Now, I am gonna add the addPublication mutation resolver to the graphql-resolvers.js file:
I defined the mutation, and it returns a string. Of course, if you need more sophisticated testing of mocked mutation, you can add code here.
How to use mocked mutation in the app
Add components \ publicationForm \ addPublication.gql.js file:
As you can see, here also I used the @client directive to define mock mutation
Update the publicationForm.jsx component code:
Here I added the logic responsible for performing mutation. As for queries - it work the same with mocked mutation as with real ones.
Results in the browser:
How to use live data when it is ready
Ok, so we have mocked some fields, queries, and mutations, and you may ask what you should do when the backend team implements all requested fields and operations in the API.
It’s pretty simple. You should:
-
1. remove @client annotations - when a particular field or operation is ready, just remove the @client directive from query/mutation
-
2. remove client resolvers - remove resolvers because they are not needed anymore when data is populated from API
-
3. remove client type definitions - same here, the schema should be implemented on the backend side, so it’s no need anymore
Summary
In this article, I showed you how to mock GraphQL queries and mutations. Compared to a REST API, mocking GraphQL queries is much easier. The subsequent transition to real data only really involves a change in GraphQL queries and resolvers’ removal. In my opinion, mocking data in GraphQL is much easier than in REST, which is unquestionably beneficial for everyone.
When you want to mock some fields or operations on the client side using Apollo Client, please follow these steps:
-
Create client-side GraphQL schema
-
Define custom resolvers/read function
-
Use @client directive in queries/mutations
I hope you liked this article. Thanks for reading!