Creating simple mock server using nodejs

Posted on 11 Aug 2021
Updated on 13 Aug 2021

When do we need mock server?

Sometimes its not possible to connect to the backend even if you are using a proxy. Having mock-apis in hand just makes UI development easier. Sometimes you need to test your screens for various error scenarios like 404, 504 etc.

What about json-server?

Well, it all depends on your use case. If your app follows rest principles and api calls are structured accordingly, you can always just directly spawn a new instance of json-server and it should be sufficient.

But in practice, what you need is

  • Lightweight server which should not need build/deploy etc
  • Should be quick to start/restart so that any file change can be done quickly
  • Can load data from files depending on the route
  • Can simulate service errors like 400, 403, 500 etc
  • Should be de-coupled from your dev server

Nodejs http module

Of course you can use any tech stack for the above requirements but generally front-end devs are familiar with Javascript and having a node library for the same makes it a breeze.

  • Import the http and fs(optional) modules. You can always use simple strings if you don’t want to deal with files.
const http = require("http");
const fs = require("fs");
  • Create constants or maybe a separate file altogether mock-routes.json to store the URL to data mapping.
{
  "/user-service/user/1234567890": "user/data.json",
  "/user-service/user/0987654321": "user/data2.json",
  "/role-service/role/manager": "user/manager.json"
}
  • Use createServer method to create an instance of the server
let routes = JSON.parse(fs.readFileSync("mock-server/mock-routes.json", "utf8"));
const requestListener = function(req, res) {
  // Set contentType properly as per need
  res.writeHead(200, {"Content-Type": "application/json"});
  // Return response
  res.end(fs.readFileSync(__dirname + routes[req.url], "utf8"););
};

// pass on the request listener
const server = http.createServer(requestListener);

// set port number as per choice
server.listen(7000);
  • Log the routes to standard output for additional debugging
console.log("----- Routes -----");
console.log(routes);
console.log("----- Routes -----");
  • If you need custom headers. You can always put this in a conditional statement.
  res.setHeader("custom-header", 999999);
  • Optional fallback if no route matched
  // Read file only if route matched
  if (routes[req.url]) {
    res.writeHead(200, {"Content-Type": "application/json"});
    response = fs.readFileSync(path + routes[req.url], "utf8");
  } else {
    res.writeHead(404, {"Content-Type": "applciation/json"});
  }
  • Set content type properly as per the resource if you want to serve data other than json
  // For various static resources
  if (req.url.includes("fonts")) {
    contentType = "application/x-font-ttf";
    path = path + "/fonts/";
  } else if (req.url.includes("img")) {
    contentType = "image/svg+xml";
    path = path + "/images/";
  } else if (req.url.includes("png")) {
    contentType = "image/png";
    path = path + "/images/";
  } else {
    contentType = "application/json";
    encoding = "utf8";
  }
  • Optionally log the hits for troubleshooting
  // Output redirection path
  console.log("\n", req.url, " -> ", routes[req.url]);

Start the server

node mock-server.js

Output

Server running

Alternatives