Mocking API servers with Mock Service Worker - MSW
Tags: webdev, javascript, mock, msw
Published: 2022-11-29 00:57:08

by [David Ekete](https://blog.openreplay.com/authors/david-ekete)

A mock API server is an imitation or clone of a real back-end server that mimics a real server by intercepting requests and providing realistic responses.

Mock API servers are helpful during development and testing when a live server is unavailable or does not need to be polluted with test data.

Mock Service Worker (MSW) is an API mocking library that uses the Service Worker API to intercept requests. This tutorial will teach you how to create a mock API server for your applications using MSW.

## Setting up Your Development Environment

To get started with MSW, install it in your project's root directory by running the command below:

```
npm install msw
```

Next, create a `mocks` folder in your `src` folder by running the command below:

```
mkdir mocks
```

This folder will contain all the files related to the mock API server.

Finally, create a `handler.js` and a `browser.js` file in your `mocks` folder. The `handler.js` file will contain all the route handler logic for the application. The `browser.js` file is where you will configure and start your service worker for request interceptions.

## Defining REST Mocks

Since you're mocking a REST API, in your `handler.js` file, import `rest` from `msw`.

Like so:

```javascript
//handler.js
import { rest } from "msw";
```

`rest` is a namespace exposed by the MSW library that contains essential methods for mocking a REST API, such as `get` and `post`, which you can use to handle HTTP requests like GET and POST.

Next, create and export an array, `handlers`.

Like so:

```javascript
//handler.js
export const handlers = [];
```

This array will contain all the mock route handlers for your application. In this tutorial, you will create, Create, Read, Patch, and Delete (CRUD) mock endpoints for your application.

Next, add the following code to your `handler.js` file:

```javascript
const blogs = [
    {
      "id": 1,
      "title": "sunt aut facere",
      "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum"
    },
    {
      "id": 2,
      "title": "qui est esse",
      "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel"
    },
    {
      "id": 3,
      "title": "ea molestias quasi",
      "body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur"
    }
];
```

The code block above will serve as a database for your mock API server. Note that your test data should implement the same schema your real API server will implement to ensure that your mock server produces more realistic results.

Next, create a mock route handler for a GET request to `api/blogs` by adding the code block below to your `handlers` array. This endpoint should return all the blogs:

```javascript
rest.get("/api/blogs", (req, res, ctx) => {
    return res(ctx.json(blogs));
  }),
```

We called the `get` method on `rest` in the code block above. This method takes two arguments, a path and a [response resolver](https://mswjs.io/docs/basics/response-resolver). A response resolver is a callback function that contains all the logic required to resolve a request. It takes three arguments, `request` (`req`), `response` (`res`), and `context` (`ctx`). 
`request` contains all the details about the current request. 
`response` is used to construct the mock response. 
`context` contains request-specific utility functions that help build the mock response.
Then we return the `blogs` array as JSON to the client by turning it into JSON using the `ctx.json` method and wrapping it in `res`.

Next, create a mock route handler for a GET request to `api/blogs/:id` by adding the code block below to your `handlers` array:

```javascript
rest.get("/api/blogs/:id", (req, res, ctx) => {
    //Extracting id from URL
    const id = req.params.id;
    //Getting blog from db (array)
    const blog = blogs.find((blog) => blog.id === id);

    //Sending response
    if (blog) {
      return res(ctx.json(blog));
    } else {
      return res(ctx.json({ message: "Blog not found" }));
    }
  }),
```

This endpoint should return a single blog post.


Next, create a mock route handler for a POST request to `api/blogs/new` by adding the code block below to your `handlers` array. 

```javascript
rest.post("/api/blogs/new", async (req, res, ctx) => {
    //Getting request body in json
    const blog = await req.json();

    //Assigning ID
    blog.id = blogs.length + 1;


    //Adding blog to db (array)
    blogs.push(blog);

    //Sending response and setting status code
    return res(
      ctx.status(201),
      ctx.json({
        id: blogs.length + 1,
        blog,
      })
    );
  }),
```

This endpoint should return and add a new blog to the existing list.

Next, create a mock route handler for a DELETE request to `api/blogs/:id` by adding the code block below to your `handlers` array:

```javascript
rest.delete("api/blogs/:id", (req, res, ctx) => {
    const id = req.params.id;
    const blogIndex = blogs.findIndex((blog) => blog.id === id);

    //Removing blog from db (array)
    blogs.splice(blogIndex, 1);

    return res(ctx.json({ message: "Deleted successfully" }));
  }),
```

This endpoint should delete the specified blog post.

Next, create a mock route handler for a PATCH request to `api/blogs/:id` by adding the code block below to your `handlers` array:

```javascript
rest.patch("api/blogs/:id", async (req, res, ctx) => {
    const id = req.params.id;
    const reqBody = await req.json();
    const blog = blogs.find((blog) => blog.id === id);

    //Updating blog
    blog.title = reqBody.title;
    blog.body = reqBody.body;

    //Sending response
    return res(ctx.json({ message: "Updated successfully" }));
  }),
```

This endpoint should edit the specified blog post.

Your finished handlers array should look like the code block below:

```javascript
export const handlers = [
  rest.get("/api/blogs", (req, res, ctx) => {
    return res(ctx.json(blogs));
  }),

  rest.get("/api/blogs/:id", (req, res, ctx) => {
    //Extracting id from URL
    const id = req.params.id;
    //Getting blog from db (array)
    const blog = blogs.find((blog) => blog.id === id);

    //Sending response
    if (blog) {
      return res(ctx.json(blog));
    } else {
      return res(ctx.json({ message: "Blog not found" }));
    }
  }),

  rest.post("/api/blogs/new", async (req, res, ctx) => {
    //Getting request body in json
    const blog = await req.json();
    //Creating unique id
    currentId += 1;

    //Assigning ID
    blog.id = currentId;

    //Adding blog to db (array)
    blogs.push(blog);

    //Sending response and setting status code
    return res(
      ctx.status(201),
      ctx.json({
        id: currentId,
        blog,
      })
    );
  }),

  rest.delete("api/blogs/:id", (req, res, ctx) => {
    const id = req.params.id;
    const blogIndex = blogs.findIndex((blog) => blog.id === id);

    //Removing blog from db (array)
    blogs.splice(blogIndex, 1);

    return res(ctx.json({ message: "Deleted successfully" }));
  }),

  rest.patch("api/blogs/:id", async (req, res, ctx) => {
    const id = req.params.id;
    const reqBody = await req.json();
    const blog = blogs.find((blog) => blog.id === id);

    //Updating blog
    blog.title = reqBody.title;
    blog.body = reqBody.body;

    //Sending response
    return res(ctx.json({ message: "Updated successfully" }));
  }),
];
```



<h2>Open Source Session Replay</h2> 

_<a href="https://github.com/openreplay/openreplay" target="_blank">OpenReplay</a> is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data._

![OpenReplay](https://blog.openreplay.com/banner-blog_1oYPGT.png)

_Start enjoying your debugging experience - <a href="https://github.com/openreplay/openreplay" >start using OpenReplay for free</a>._








## Integrating MSW with your Application (Browser)

After creating the mock route handlers for your application, you will need to integrate MSW into your application by creating a service worker that will intercept the requests made by your application.

Note that you won't need to write any service worker code yourself. Instead, you will use a dedicated MSW CLI to generate it.

Run the command below to generate the required service worker files:

```javascript
npx msw init public/ --save
```

Note: If you are not working with Create React App, replace "public/" with the relative path to your server's public directory.

Next, in your `browser.js` file, import `setupWorker` from `msw` and your `handlers` array. Like so:

```javascript
//browser.js
import { setupWorker } from "msw";
import { handlers } from "./handlers";
```

Then, create and export a variable, `worker`, and initialize it by calling the `setupWorker` method and passing a de-structured `handlers` array as an argument.

Like so:

```javascript
//browser.js
export const worker = setupWorker(...handlers);
```

Finally, conditionally import `worker` from your `browser.js` file, and activate it by calling the `start` method. Like so:

```javascript
if (process.env.NODE_ENV === "development") {
  const { worker } = require("./mocks/browser");
  worker.start();
}
```

Once your service worker is enabled, "[MSW] Mocking enabled" should be displayed on your console as shown in the image below:

![1](https://blog.openreplay.com/images/mocking-api-servers-with-mock-service-worker-msw/images/image01.png)


## Conclusion

This tutorial covered the basics of mocking an API server using the MSW package. You can take your API mocking to a different level by implementing a mock database using the `msw/data` package, which you can use to mimic an actual database.


<h2>Open Source Session Replay</h2> 

_<a href="https://github.com/openreplay/openreplay" target="_blank">OpenReplay</a> is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data._

![OpenReplay](https://blog.openreplay.com/banner-blog_1oYPGT.png)

_Start enjoying your debugging experience - <a href="https://github.com/openreplay/openreplay" >start using OpenReplay for free</a>._



[![newsletter](https://blog.openreplay.com/newsletter_Z1P0UIP.png)](https://newsletter.openreplay.com/)