Going to mock GraphQL
Tags: mock, graphql, react
Published: 2022-01-28 11:46:11

I am writing a front end with React/JavaScript. I heard GraphQL and I do like it. I want to replace the REST API.

But I do not want to build the back end before I finish my front end, that mean I need a **fake** API. So there are two ways for me:

* Build a server that can deal with the request and return the fake response.
* Or we can... yes, mock those function.

IF YOU HAVE GOOD IDEA, FEEL FREE TO TELL ME PLEASE: peterlitszo at gmail, I WILL CHANGE/UPDATE IT SOON!

## First Part - Build a server.

This post have a easy setup that build a fake server:

https://dev.to/ekafyi/serving-nothing-through-graphql-58cc

Apollo is a package to build a GraphQL client, here is the document to build mock server:

https://www.apollographql.com/docs/apollo-server/testing/mocking/

But I do not want to build this. The reason is easy: In computer the port can only hold by one process. That mean I need to hold two process (the first is the React development (with HMR) process, the second is the server process), and I need to change the variable by the environment (dev or release).

## Second Part - Mock.

This is the way I am using. I am using [msw](https://mswjs.io) now.

In the main javascript file, I add this part, so the msw will get the request in browser and then return the fake data, which defined in file `./src/mock/browser.js`:
``` js
// ./src/index.jsx

if (process.env.NODE_ENV === 'development') {
  const { worker } = await import('./mock/browser');
  worker.start();
  console.log('Add mock...');
}
```

Now it is time to create file `./src/mock/browser.js`:
``` js
// ./src/mock/browser.js

import { setupWorker, graphql } from 'msw';
import { filter, isUndefined } from 'lodash';
import { faker } from '@faker-js/faker';

// The news' data.
const new_data = {
  news: [
    {
      id: 1,
      title: 'First',
      image_uri: faker.image.abstract(undefined, undefined, true),
      content: 'First '.repeat(1000),
      summary: 'A lot of word `First`',
    },
    {
      id: 2,
      title: 'Second',
      image_uri: faker.image.abstract(undefined, undefined, true),
      content: 'Second '.repeat(1000),
      summary: 'A lot of word `Second`',
    },
    {
      id: 3,
      title: 'White',
      image_uri: faker.image.abstract(undefined, undefined, true),
      content: 'White '.repeat(1000),
      summary: 'Just white',
    },
    {
      id: 4,
      title: 'Random',
      image_uri: faker.image.abstract(undefined, undefined, true),
      content: faker.lorem.paragraphs(100, '\n\n'), // markdown
      summary: 'Hello',
    },
  ],
};

// Mock the query named News
const News = graphql.query('News', (req, res, ctx) => {
  const { newsId } = req.variables;
  const news = isUndefined(newsId)
    ? news_data.news
    : filter(news_data.news, (new_) => parseInt(newsId) === new_.id);
  return res(ctx.data({ news }));
});

// The log's data.
const log_data = {
  users: [
    {
      id: 1,
      name: 'Peter',
      emails: ['peterlitszo at gmail.com'],
      password: 'admin123',
      isAdmin: true,
    },
  ],
};

// Mock the query named Log.
const Log = graphql.query('Log', (req, res, ctx) => {
  const { email } = req.variables;

  return res(
    ctx.data({
      ...filter(log_data.users, (o) => o.emails.includes(email)),
    }),
  );
});

// build and export the worker.
const handlers = [News, Log];

export const worker = setupWorker(...handlers);
```