DEV Community

Hélio Marcondes
Hélio Marcondes

Posted on

API mocking with Mock Service Worker + Vue.js

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 }
}


Enter fullscreen mode Exit fullscreen mode

./screens/Groups/Groups.vue



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

const { groups } = getGroupData()


Enter fullscreen mode Exit fullscreen mode

But after a little research I found the Mock Service Worker 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


Enter fullscreen mode Exit fullscreen mode

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",
      },
    ]);
  }),
];


Enter fullscreen mode Exit fullscreen mode

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);


Enter fullscreen mode Exit fullscreen mode

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



npx msw init <PUBLIC_DIR>


Enter fullscreen mode Exit fullscreen mode

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");
});


Enter fullscreen mode Exit fullscreen mode

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>


Enter fullscreen mode Exit fullscreen mode

And here is the final result:
Final result

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!

Top comments (4)

Collapse
 
kettanaito profile image
Artem Zakharchenko

Thanks for writing this!

Looks like something got left out from this sentence:

On my example I use "public" as a , after you execute

Otherwise, a great overview of using MSW. Glad it helped you ship.

Collapse
 
heliomsolivas profile image
Hélio Marcondes

I fixed, thank you!

Collapse
 
maldestor95 profile image
maldestor95

Great article!

When you will go to production, I suppose you will remove the public directory and disable the worker in the main vuejs file?

Collapse
 
decodecoder profile image
@nezlicodes

Was really helpful, thank you!