DEV Community

Cover image for Spawn an HTTP server from your Mock Service Worker request handlers.
Artem Zakharchenko
Artem Zakharchenko

Posted on

Spawn an HTTP server from your Mock Service Worker request handlers.

When Mock Service Worker was released, it had a clear mission to enable API mocking without the need to spawn and maintain an actual HTTP server. This purposeful restriction, among a few other core principles, has led to thousands of developers writing declarative, agnostic, and reusable mocks every day, prototyping amazing applications and delivering stunning products with confidence.

While our "you don't need a mocking server" principle still stands strong today, we listen closely and analyze all the great feedback that our users share with us in order to improve the project and increase the amount of use cases it could cover.

Today, I'm excited to tell you about a project that David Idol and I have collaborated on with a goal to bring Mock Service Worker to more challenging usage contexts. We named it "http-middleware".

GitHub logo mswjs / http-middleware

Spawn an HTTP server from your request handlers or apply them to an existing server using a middleware.


The Concept

The premise of http-middleware is extremely straightforward: reuse your request handlers to create an actual HTTP server.

This project is designed to cover more complex use cases when the standard Mock Service Worker approach isn't sufficient. Such use cases include:

  • Adding the ability to curl your mock definitions, for example, for local debugging;
  • Integrating API mocking in complex application architecture (i.e. with dockerized apps).
  • Prototyping Node.js server development.

Note that this project is not a go-to solution for API mocking, and you should always favor Mock Service Worker instead. It's created to handle complex use cases and you'd know when you need it. As a rule of thumb: when in doubt, prefer MSW.

Learn more about how to get started with MSW.


The Usage

The "http-middleware" project is so concise that I've decided to write a brief usage tutorial right here, right now. Let's get a server running in 2 minutes with your request handlers being the source of truth.

First, create a project if you don't have one already:

$ npm init -y
Enter fullscreen mode Exit fullscreen mode

Then, install the necessary dependencies:

$ npm install express msw @mswjs/http-middleware --save-dev
Enter fullscreen mode Exit fullscreen mode

To keep things simple, let's have a single server.js file where we will declare our server:

$ touch server.js
Enter fullscreen mode Exit fullscreen mode

Finally, use the createServer function to spawn an Express server. Provide it with the request handlers you want to be responsible for producing responses:

// server.js
const { rest } = require('msw')
const { createServer } = require('@mswjs/http-middleware')

const httpServer = createServer(
  rest.get('/', (req, res, ctx) => {
    return res(ctx.text('Hello world'))
  })
)

httpServer.listen(9090)
Enter fullscreen mode Exit fullscreen mode

Learn more about writing request handlers with Mock Service Worker. You can reuse the same handlers you write in tests, local development, and debugging.

Now run your server:

$ node server.js
Enter fullscreen mode Exit fullscreen mode

Try making a GET http://localhost:9090 request. You'll see that the response was resolved based on the request handler you've specified:

200 OK
Content-Type: text/plain;

"Hello world"
Enter fullscreen mode Exit fullscreen mode

Done 🎉

Adding to an existing server

Alternatively, you can apply request handlers via a middleware, which is handy in case you already have a server:

// existing-server.js
import { rest } from 'msw'
import { createMiddleware } from '@mswjs/http-middleware'
import { app } from './app'

app.use(
  createMiddleware(
    rest.get('/', (req, res, ctx) => {
      return res(ctx.text('Hello world'))
    })
  )
)
Enter fullscreen mode Exit fullscreen mode

The Cherry on Top

With request handlers acting as the source of truth, you get the same benefits as when using MSW: shared API mocking logic across different environments and purposes.

I can't stress enough how important it is to have a clean, deterministic testing setup. There is absolutely no reason to install 3 different libraries for API mocking just because you want to mock the same API in an integration test, and then in an end-to-end test, and then to debug an irksome data-driven bug.

Mock Service Worker allows you to write your API mocks once and reuse them anywhere later: when working on the app, when testing it in Node.js, when running automated tests in Cypress, when debugging. All that using the same familiar consistent syntax. Don't miss out.

GitHub logo mswjs / msw

Industry standard API mocking for JavaScript.

Embrace the ecosystem

By leveraging libraries like @mswjs/data, you can have data-driven type-safe API mocking reused across the entire stack. Develop and iterate on your next product with the speed of light by the flexibility Mock Service Worker and its ecosystem gives you.


Afterword

We're excited to see what impact this small package will have in your development workflow! Make sure to follow Mock Service Worker on Twitter to get the latest news and be notified about many upcoming features.

We also highly encourage you to contribute to the http-middleware package with your ideas and feedback on GitHub:

GitHub logo mswjs / http-middleware

Spawn an HTTP server from your request handlers or apply them to an existing server using a middleware.

Stay awesome ❤️

Top comments (5)

Collapse
 
philw_ profile image
Phil Wolstenholme • Edited

Am I right in thinking that the 'Node.js app inside Docker needs mocking' issue could be resolved by using setupServer from the main MSW package (perhaps behind an if statement linked to an environment variable or some other condition?), but the HTTP server version is preferable because it means you won't need to pollute your Node.js app with testing-specific code, you'd only need to change what server or localhost port that the Node.js app was fetching the data from?

Collapse
 
kettanaito profile image
Artem Zakharchenko

Hey, Phil.

I believe some of the use cases people had with Docker prevented them from spawning MSW within the same process, somehow. I wish I could share more but those aren't the setups I use.

the HTTP server version is preferable because it means you won't need to pollute your Node.js app with testing-specific code

I don't find this beneficial at all. One if statement is hardly pollution with test-related code. Spawning an HTTP server and then routing the traffic of your app to that server, now that's a huge change to the application's logic only for the purpose of testing.

That's why I always encourage using MSW as it's designed—to have seamless request interception. The HTTP server is mainly there so you could turn your mocks into an actual server, whichever is your reason for doing so. I've been using MSW for years and I've never had the need to spawn a server from it. But I acknowledge that use cases are different in the wild, and having such an option is crucial for some developers.

Collapse
 
philw_ profile image
Phil Wolstenholme

Thanks for the reply :) I am also in the one-if-statement-isn't-the-end-of-the-world camp. We don't use MSW at work at the moment but I've recently tried it out on my personal site so now I'm going to see how people feel about using it at work too. Thanks for all your work on MSW!

Collapse
 
controlplusb profile image
Sean Matheson

Ah this approach saved me so much pain. I migrated from a pure SPA to Next.js and needed a way to consistently call my mocks across the browser and server environment. The problem was my mocks were stateful. I tried to recreate a backend like experience within them to prove the functionality before implementing the backend. Thank you for this!

Collapse
 
kettanaito profile image
Artem Zakharchenko

I'm so happy to hear that, Sean!
We've developed http-middleware precisely to ease setup migrations like yours. I'm glad to see it finds its applications in the wild.

Don't hesitate to let us know about any obstacles you encounter while using the library in GitHub issues.