How to annotate Express middlewares with JSDoc?

I'm trying to document an Express middleware, but the build-in validation tool in WebStorm tells me that types are incorrectly assigned in the following JSDoc block:

/**
 * My middleware.
 *
 * @param {Object} req
 * @param {Object} res
 * @param {Function} next
 * @return {Object}
 */
exports.show = function(req, res, next) {
    ...
};

In Express sources, I didn't find any @typedefs to help me. Also, I want to avoid things like @param {*}.

What is the correct way to document Express middleware using JSDoc? Thanks for any help.


You can document your middleware with

const express = require("express");

/**
 * @param {express.Request} req
 * @param {express.Response} res
 * @param {express.NextFunction} next
 */
function (req, res, next) {}

when you have middleware that add attribute to req, you can also add them with

const express = require("express");

/**
 * @param {express.Request & {specialParam1 : string, specialParam2 : any}} req
 * @param {express.Response} res
 * @param {express.NextFunction} next
 */
function (req, res, next) {}

or event better, create a typedef for each source of new elem added on "req" and use "&" to create a type combining them all.


Use DefinitelyTyped

  1. Install express types npm install --save-dev @types/express
  2. use e.Response as usually @param {e.Response} res

More types

  • in file /node_modules/@types/express/index.d.ts
  • for Response it is e.Response because:

... declare namespace e { ... export interface Response extends core.Response { } ...

WebStorm

install types via Settings > Languages & Frameworks > Javascript > Libraries > @types/express


First, we agree that middleware are functions; no special type declaration will generally be warranted. Beyond that, middleware tend to be highly decoupled—modular—which means the @module tag is usually applicable (and this has nice consequences when you run jsdoc).

/**
 * Description of my middleware.
 * @module myMiddleware
 * @function
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 * @param {Function} next - Express next middleware function
 * @return {undefined}
 */

The return tag is optional depending on your style guide, since middleware don't return a value. Finally, contrary to what Nick and mmm claim, the next parameter is a function.

http://expressjs.com/en/guide/using-middleware.html

Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.

next isn't a fancy Express-internal concoction; Express passes each middleware function the request, the response, and the next middleware function in the stack, like this:

mw1 = function(req, res, next){}.bind(undefined, req, res, mw2)
mw2 = function(req, res, next){}.bind(undefined, req, res, mw3)

The value of next within the scope of mw1 is mw2.


You can not only JsDoc the parameter types and descriptions, and but also their expected members.

/**
 * 
 * @module myMiddleware
 * @function
 * @param req {Object} The request.
 * @param res {Object} The response.
 * @param req.params.foo {String} The foo param.
 * @param req.query.bar {String} The bar query.
 * @param req.body {Object} The JSON payload.
 * @param {Function} next
 * @return {undefined}
 */
function foo(req, res, next){
}

[2021-03-02 Update] Original answer is like 100% JSDOC + 0% typescript, but I found a 20% JSDOC + 80% typescript (pure definition) solution. In typescript github, it mentioned this method. See the final paragraph in post.

I combine other answer and modify some code,
it could include all of the methods/properties defined on express.Request and event custom request body.
It could not only use in request.body, but also support in req.query.
That because express.Request support generics, so we could use this in JSDoc.

First, remember to install @types/express with npm install --save-dev @types/express.

Second, setup like following code.

// @ts-check
/**
 * @typedef {object} showRequestBody
 * @property {string} name this is name in request body
 * @property {number} age this is age in request body
 * 
 * @typedef {object} showRequestQuery
 * @property {string} name this is name in query
 * @property {number} age this is age in query
 * 
 * @param {import('express').Request<{}, {}, showRequestBody, showRequestQuery>} req
 * @param {import('express').Response} res 
 * @param {import('express').NextFunction} next 
 */
exports.show = function(req, res, next) {
};

Note: I use it in vscode.
I leave answer here, and I hope this will help other people also have this question.


other methods/properties defined on express.Request, for example req.headers


req.body hint


req.query hint

20% JSDOC + 80% typescript

The following example doesn't need tsconfig.json or install extra tsc.
But, you couldn't use jsdoc to generate documentation.

With import + export definition

If you want to extend interface with importing some module, you need to use export in definition. Then import it in JSDOC.

enter image description here

enter image description here

Without import + export definition

If you don't want to import custom definition in JSDOC, you could just define the interface without import and export. Then, you could directly use it in JSDOC.

enter image description here

enter image description here

Extend the express module

There is another way to build custom interface, just use declare module to extend the interface. You could even define custom method.

enter image description here

enter image description here

enter image description here