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 @typedef
s 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
- Install express types
npm install --save-dev @types/express
- 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.
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.
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.