It’s useful to be able to provide a unified response “envelope” when creating a REST API. This envelope can contain metadata, data and information on errors and warnings.

To do so with express for nodejs you can add custom functions to the request prototype and declare them in a module augmentation.

import { Response } from "express-serve-static-core";
import { response } from "express";

// augment the `express-serve-static-core` module
declare module "express-serve-static-core" {
  // first, declare that we are adding a method to `Response` (the interface)
  export interface Response {
    respondWithData(data: any): this;
  }
}

// now actually add it to `response` (the prototype)
response.respondWithData = function(data) {
  return this.json({ errors: null, data: data });
};

Possibly confusing:

The value request imported from express refers is the prototype of request objects passed to handler functions; it implements the Request interface exported by express-serve-static-core

The interface Request imported from express-serve-static-core refers to a Typescript interface and has no runtime meaning

After we’ve declared the method and added it to the prototype, we can now call it from our route handler:

app.get("/foo", async(req, res) => {
  res.respondWithData({ success: true });
});