DEV Community

Cover image for What is MSW and how to use it in NextJS
The Teabag Coder
The Teabag Coder

Posted on

What is MSW and how to use it in NextJS

What is MSW?

  • MSW is short for mock service worker.
  • A network mocking library for your UI using service worker

- “network mocking” means your code won’t know the different between fake and real APIs

Why use MSW?

Notable benefits:

  • Don't have to create mock data in your frontend code
  • Don't have to go back to modify your frontend code after APIs finished.
  • Can test your UI with various API responses (e.g., success, failure, delays, or specific error codes)
  • Can work in both frontend and backend
  • Can run locally instead of depends on 3rd party tools or live services.

How to use MSW in your NextJS project?

  • Install MSW npm install msw@2.0.14 --save-dev (latest version is having issues)
  • Generate worker script npx msw init public --save
  • Create a folder called mocks inside your src folder with 3 files browser.ts server.ts handlers.ts
  • In your app folder create msw-provider.tsx
  • handlers.ts describes your mock
import { http, HttpResponse } from "msw";
export const handlers = [
    // Intercept "GET https://example.com/user" requests...
    http.get("https://example.com/user", () => {
        // ...and respond to them using this JSON response.
        return HttpResponse.json({
            id: "c7b3d8e0-5e0b-4b0f-8b3a-3b9f4b3d3b3d",
            firstName: "John",
            lastName: "Maverick",
        });
    }),
];
Enter fullscreen mode Exit fullscreen mode
  • browser.ts setups msw for client side
import { setupWorker } from "msw/browser";
import { handlers } from "./handlers";
export const worker = setupWorker(...handlers);
Enter fullscreen mode Exit fullscreen mode
  • server.ts setups msw for server side
import { setupServer } from "msw/node";
import { handlers } from "./handlers";
export const server = setupServer(...handlers);
Enter fullscreen mode Exit fullscreen mode
  • msw-provider.tsx enables msw in your app for client side
"use client";
import { Suspense, use } from "react";
const mockingEnabledPromise =
    typeof window !== "undefined" && process.env.NODE_ENV === "development"
        ? import("../mocks/worker").then(async ({ worker }) => {
                await worker.start();
          })
        : Promise.resolve();

export function MSWProvider({ children }: Readonly<{ children: React.ReactNode }>){
    // If MSW is enabled, we need to wait for the worker to start,
    // so we wrap the children in a Suspense boundary until it's ready.
    return (
        <Suspense fallback={null}>
            <MSWProviderWrapper>{children}</MSWProviderWrapper>
        </Suspense>
    );
}

function MSWProviderWrapper({ children }: Readonly<{ children: React.ReactNode }>){
    use(mockingEnabledPromise);
    return children;
}
Enter fullscreen mode Exit fullscreen mode
  • Use msw-provider In your layout.tsx like this
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
    <MSWProvider>{children}</MSWProvider>
</body>
Enter fullscreen mode Exit fullscreen mode
  • To enable server-side mocking, add this to your layout.tsx
//enable server side mocking
if (process.env.NEXT_RUNTIME === "nodejs") {
    const { server } = require("../mocks/server");
    server.listen();
}
//right before layout function
export default function RootLayout({
...
Enter fullscreen mode Exit fullscreen mode

Let's test msw on both environments client-side and server-side

  • Create a client-component.tsx in your src mine is src/components/client-component.tsx
  • Make a fetch request to https://example.com/user as we described in handlers.ts
"use client";
import { useEffect } from "react";
const getUser = async () => {
    console.log("client-side fetching");
    const response = await fetch("https://example.com/user");
    const json = await response.json();
    console.log(json);
};

export default function ClientComponent() {
    useEffect(() => {
        getUser();
    }, []);
    return <div>client component</div>;
}
Enter fullscreen mode Exit fullscreen mode
  • In your page.tsx make a similar request to https://example.com/user
import ClientComponent from "@/components/client-component";
async function fetchApi() {
    console.log("server fetching");
    const response = await fetch("https://example.com/user");
    const json = await response.json();
    console.log(json);
}

export default async function Home() {
    const user = await fetchApi();
    return (
        <div>
            page
            <ClientComponent />
        </div>
    );
}
Enter fullscreen mode Exit fullscreen mode

You should see user data being logged in both terminal and browser console.

Thank you for reading this far. Till next time!

Source code: https://github.com/TheTeabagCoder/msw-nextjs-sample

Top comments (0)