Mocking Your API's Calls Using Mocking Service Worker (MSW)
Tags: javascript, webdev, testing
Published: 2023-07-01 22:00:02

Hi, lovely people! It's a pleasure to have you here again!

![Patrick Heart Image Meme](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4qk9a2eds9vm9r3w1flb.png)

Today, I'm gonna talk about a library called `Mocking Service Worker` or better know as `MSW`.

Sometimes, when you are working in some feature, both backend and frontend team start to developing together. Or maybe the frontend team, start the development of the feature first and the API's sometimes are not ready yet. Or another situation, you start your frontend project first, and only after that will start the development of the backend and the API's.

But the fact is, you don't have the API's or your endpoins ready yet. So what you do?

Probably your answer it will be: "Well... I'll mock the response of my API". And yes, commonly we just mock the response that we expect. 

But in `ALL` cases we will need to refact the code to really integrate with the API and make sure that our code is callling the endpoint with the right contract that was defined.

Also, we need to add or update the tests to ensure that a call to the API was made with the correct data.

BUT what if we could make a call to a `fake API` and we don't need to worry with refact all the code after with the real integration or add or update our tests. This will make the frontent development of the feature more dynamic. 

When the API is ready we just change the url and everything will be working. But until there, we will use a fake API to mock the calls.

So in this case, I introduce to you the `MSW`.
MSW is a library where we can add in our project, and a `Service Worker` will be responsible to intercept the calls and respond to our client as a "fack backend" response.

Mock by intercepting requests on the network level. Seamlessly reuse the same mock definition for testing, development, and debugging. MSW, also can work with REST API and GraphQL.


![Diagram how the MSW works](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y2a7id62gfnwtd972gam.png)

So now that you are familiar with MSW concepts let's apply an example, creating a React project. First we will simulate and call the API without MSW and after that we will integrate it into the project.

## Creating the project

I will be using the `Vite` to create our react boilerplate using the command:

```sh
yarn create vite msw-example --template react-ts
```

After that, enter on the project and install the dependencies:

```sh
cd msw-example
yarn
```

I will remove the `App.css` and in our `index.css` add:

```css
body {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: Arial, Helvetica, sans-serif;
}

.container {
  display: flex;
  flex-direction: column;
}

.card {
  width: 50%;
  display: flex;
  flex-direction: column;
  margin: 3px;
  border: 1px solid #000;
}

button {
  width: 200px;
  background-color: #1e40af;
  color: #fff;
  font-size: medium;
  padding: 15px;
  border-radius: 4px;
}

button:hover {
  background-color: #2563eb;
  cursor: pointer;
}
```

Let's create our `types` on `src/types/user/index.ts`:

```ts
export interface User {
  id: string;
  name: string;
  userName: string;
  avatar?: string;
  email: string;
}
```

Now create our `service` on `src/services/user/index.ts` that will be responsible to call the API's. 

```ts
import { User } from "../../types/user";

export class UserService {
  static async getUsers(): Promise<User[]> {
    // Fetch User API
    const mockUsers = new Array(3).fill(null).map((_, index) => ({
      id: index.toString(),
      email: "kevin@gmail.com",
      name: "kevin",
      userName: "uehara.kevin",
      avatar:
        "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/54.png",
    }));

    return Promise.resolve(mockUsers);
  }
}
```

Notice that I'm mocking the users `on code`. I'm creating an array with 3 users with the same data and returning as a promise.

Now in our `App.tsx`, let's udpate the code with:

```tsx
import { useState } from "react";
import { User } from "./types/user";
import { UserService } from "./services/user";

function App() {
  const [users, setUsers] = useState<User[]>([]);

  const handleFetchUsers = async () => {
    const users = await UserService.getUsers();
    setUsers(users);
  };

  return (
    <div className="container">
      <h1>Mocking Service Worker Example</h1>
      <button onClick={handleFetchUsers}>Fetch Data</button>
      {users.map((user) => (
        <div className="card" key={user.id}>
          <img src={user.avatar} width="100px" height="100px" />
          <label>Name: {user.name}</label>
          <label>UserName: {user.userName}</label>
          <label>Email: {user.email}</label>
        </div>
      ))}
    </div>
  );
}

export default App;
```

Now running the project, the result will be:

![Gif Application running without msw](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fswacms39emjdtlnz0qm.gif)

We are just mocking the response in our `code` and any request is made.

Now Let's play with `MSW`.

First let's add as development dependency:

```sh
yarn add -D msw @faker-js/faker 
```

We are adding two dependencies, the MSW and the `faker` (not necessary) but it will generate dynamic fake data for our project.

Let's create the MSW Service worker, that will be responsible to intercept the calls and return on network level. (the `public/` can change if you are using some frontend tool, for example I'm using vite. If you are using Angular, for example is diffent. For this [read the docs](https://mswjs.io/docs/getting-started/integrate/browser))

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

This command will create a file `service worker` on your `/public` folder called `mockServiceWorker.js`.

Now, let's create the handlers, that we will map the `endpoints` of our API. So create a folder called `src/mocks`, and inside this folder, create a file called `handler.ts` with this code:

```ts
import { rest } from "msw";
import { faker } from "@faker-js/faker";

export const handlers = [
  rest.get("/users", (_, res, ctx) => {
    const mockUsers = new Array(3).fill(null).map(() => ({
      id: faker.number.int(),
      userName: faker.internet.userName(),
      name: faker.person.fullName(),
      email: faker.internet.email(),
      avatar: faker.image.avatar(),
    }));

    return res(ctx.status(200), ctx.json(mockUsers));
  }),
];
```

Notice that the logic of create the mock, the we created on our Service, now it's in our handler mock API. And now we are using the `faker` to generate dynamic data.

Now in the same folder, we will create the file called `browser.ts`, where we will create the setup for our worker:

```ts
import { setupWorker } from "msw";
import { handlers } from "./handler";

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

Notice, that we can create a list of handlers for each mock of API if we need and pass on `setupWorker`.

Let's change the file `main.tsx` to run the MSW `ONLY` in development mode:

```tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./index.css";

if (import.meta.env.DEV) {
  const { worker } = await import("./mocks/browser.ts");
  worker.start();
}

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
```

So we just want to start the MSW on development mode, because on production we will be using the real API integrated.

To finish, just let's update our service on `src/services/user/index.ts`:

```ts
import { User } from "../../types/user";

export class UserService {
  static async getUsers(): Promise<User[]> {
    const users = await fetch("/users");
    return users.json();
  }
}
```

Now, starting the app:

On console, we will notice that there is a message that msw is working and enabled:

![Console Output that the MSW is enabled](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wl5tum3965oqeo0nj92o.png)


![Gif of our application running with MSW](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zs79yra4bw27kldfuo8b.gif)

And that's it! Now our service worker is intercepting all calls of our API (thinking that is not done yet) and we can integrate, respect the contract API and create our tests to validate the calling of our API.

MSW works as a fake backend, but will streamline frontend development without having to rely on API development or mocking data in code.

That's it folks!

Thank you so much!

Contacts:

Linkedin: https://www.linkedin.com/in/kevin-uehara/
Instagram: https://www.instagram.com/uehara_kevin/
Twitter: https://twitter.com/ueharaDev
Github: https://github.com/kevinuehara
Youtube Channel: https://www.youtube.com/channel/UC6VSwt_f9yCdvEd944aQj1Q