API mocking with Mock Service Worker + Vue.js
Tags: vue, mocking, api
Published: 2024-05-06 14:42:50

Hi everyone.

Last week I was working on a new project from scratch and encountered a common problem.

I built a big part of the frontend and my backend teammates haven't finished their part. So, I was wondering how to improve my workflow defining some mock data on frontend.

To be honest the quickly way that I usually do is to create some data in JSON format and have methods to load it, and after the API be functional I just remove the mock data to call the API.

Something like this:

./mocks/groupData.ts

```
import type { GroupInterface } from '../interfaces/Group'

export function getGroupData(): { groups: GroupInterface[] } {
  const groups: GroupInterface[] = [
    {
      id: 1,
      group: 'Group 1',
    },
    {
      id: 2,
      group: 'Group 2',
    },
  ]

  return { groups }
}
```

./screens/Groups/Groups.vue

```
<script setup lang="ts">
import { getGroupData } from '../../mocks/groupData'

const { groups } = getGroupData()
```
But after a little research I found the [Mock Service Worker](https://mswjs.io/) it's a mocking library that allows you to write client-agnostic mocks and reuse them across any frameworks, tools, and environments.

I tested on my project and it fit very well for my case, here are the steps that I used to configure the library on a Vue.js 3 project.

Step 1: Install the MSW library:

```
npm install msw@latest --save-dev
```
Step 2: Create handlers to handle the "API" requests, it will be the methods and the return of the API request:

./mocks/handlers.ts
```
import { http, HttpResponse } from "msw";

export const handlers = [
  http.get("/users", () => {
    return HttpResponse.json([
      {
        id: "c7b3d8e0-5e0b-4b0f-8b3a-3b9f4b3d3b3d",
        firstName: "John",
        lastName: "Maverick",
      },
      {
        id: "c7b3d8e0-5e0b-4b0f-8b3a-3b9f4b3d3b3e",
        firstName: "Kar",
        lastName: "Marx",
      },
    ]);
  }),
];
```

Step 3: Integrate MSW into a browser environment (other integrations are also available):

./mocks/browser.ts

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

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

Step 4: Copy the worker script to your public folder, MSW library provides a command to do this:

```
npx msw init <PUBLIC_DIR>
```
On my example I use public as a "PUBLIC_DIR", after you execute the command it will generate a file named /mockServiceWorker.js inside the public directory

Step 5: Enable mocking by calling it in main Vue.js file:

main.ts

```
import { createApp } from "vue";
import App from "./App.vue";

import "./assets/main.css";

async function prepareApp() {
  const { worker } = await import("./mocks/browser");
  return worker.start();
}

const app = createApp(App);

prepareApp().then(() => {
  app.mount("#app");
});
```
After all this configuration you should be able to call the handler that you set before, like this:

```
<script setup lang="ts">
import { onMounted, ref } from 'vue';

const users = ref<[]>([])

async function loadUserFromMsw() {
  const res = await fetch('/users')
    .then(response => response.json())
    .then(json => {
      return json
    })
    .catch(err => console.log('Error', err));

  users.value = res
}

onMounted(async () => {
  await loadUserFromMsw()
})


</script>

<template>
  <main>
    <pre>
      {{ users }}
    </pre>
  </main>
</template>
```
And here is the final result:
![Final result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/irlyryk87s28gfytwmza.png)

My final thoughts are that I can mock various routes and methods using handlers of MSW easier than my usuall way to finish the frontend with mocking data.

If you have any suggestions, please let me know. Thank you so much for reading!