Swagger Express Middleware

Swagger 2.0 middlware and mocks for Express.js

Parse Request middleware

Parses incoming requests and converts everything into the correct data types, according to your Swagger API definition. It’ll even use the default values specified in your API for any missing parameters.

You can access the parsed request using the standard Express properties and methods, such as req.body, req.params, req.query, req.get(), req.files, req.cookies, and req.signedCookies.

Example

This example uses the PetStore.yaml sample Swagger API. If you aren’t familiar with using middleware in Express.js, then read this first.

const util = require('util');
const express = require('express');
const createMiddleware = require('@apidevtools/swagger-express-middleware');

let app = express();

createMiddleware('PetStore.yaml', app, function(err, middleware) {
    app.use(middleware.metadata());
    app.use(middleware.parseRequest());

    // Show the parsed query params as HTML
    app.get('/pets', function(req, res, next) {
        res.send(
            '<h1>Parsed Query Params:</h1>' +
            '<pre>' + util.inspect(req.query) + '</pre>'
        );
    });

    app.listen(8000, function() {
        console.log('Go to http://localhost:8000/pets');
    });
});

Run the above example and then browse to http://localhost:8000/pets. You’ll see all the parsed query params for the /pets path in the PetStore.yaml. Now try adding some query parameters to the URL and see how those params get parsed.

Here are some sample links to try:

Valid:

Invalid:

Options

middleware.parseRequest(router, options)

This is the function you call to create the Parse Request middleware.

Dependencies

The Parse Request middleware requires the Metadata middleware to come before it in the middleware pipeline (as shown in the example above).

Behavior

The Parse Request middleware operates in three phases. If a parsing error occurs during any of these three phases, then the remaining phases are skipped and the error is sent to the Express error pipeline. You can then handle the error by adding your own own error-handling middleware. You might choose to respond with a friendly error message, or you may choose to ignore the error and allow the request to continue being processed as normal. Be careful if you decide to continue processing - depending on how invalid the HTTP request is, it may cause other errors in other middleware.

Phase 1 - Basic parsing

The first phase performs basic parsing of the HTTP request using third-party libraries, such as body-parser, cookie-parser, and multer. There’s nothing Swagger-specific about this phase. The only types of errors that might occur are due to malformed HTTP requests, missing or improper headers, or excessive payload sizes.

Phase 2 - Swagger parsing

The second phase performs Swagger-specific parsing. During this phase, every parameter defined in your Swagger API is checked against the HTTP request. If a Swagger parameter is missing from the request, and there’s a default value specified in the Swagger API, then that default value is used, just as if the request contained that value. If a required Swagger parameter is missing from the request, and there’s no default value, then an error is thrown.

Any Swagger parameters that are included in the request are parsed and validated according to the parameter definition. If the value doesn’t adhere to the parameter definition for any reason (such as improper data type, min/max length, min/max value, RegEx pattern, etc.), then an error is thrown.

Finally, if everything is valid, then the HTTP request values are converted to the proper JavaScript data types. For example, if you define a Swagger parameter as {type: "string", format: "date-time"}, then it will be converted to a JavaScript Date object. If you define a parameter as {type: "integer", format: "int32"}, then it will be converted to a JavaScript Number with a whole value.

Phase 3 - Path parsing

Path parameters get parsed in the third phase. Swagger and Express both support path parameters, but they use slightly different syntax. For example, the Swagger path /pets/{name}/photos/{id} is equivalent to the Express path /pets/:name/photos/:id. Express automatically parses all path parameters as strings and stores them on the req.params object. The Parse Request middleware parses path parameters according to the data type specified in your Swagger API, and updates req.params accordingly.

Tricky Behavior with req.params

TLDR

req.params is a special object in Express, and it has some very non-intuitive behavior. Use req.pathParams instead, which will always work consistently.

Details

The req.params object is a special object in Express and its properties can only be set by special param callback functions. Fortunately, Swagger Express Middleware makes this very simple. If you pass your Express app/router to the createMiddleware() function (as shown in all the examples in these docs), then the Parse Request middleware will automatically register param callbacks with your app/router. This is the recommended approach, since it also allows Swagger Express Middleware to detect your app’s settings, such as case-sensitivity and strict-routing.

Every Application and Router has its own separate param callbacks, so if you use nested routers in your project, then you need to add the param callbacks to each router. This means you need to add the Parse Request middleware to every nested router in your app if you want to use req.params in those nested routers.

Param callbacks run before each middleware in your app. But only if that middleware is bound to a path, and only if that path has parameters. So if you register middleware without a path (e.g. app.use(myMiddleware)) then req.params will be empty for that middleware. If you register middleware with a path (e.g. app.use("/users/:id", myMiddleware)), then req.params will have a property for each path parameter (id in this example). Thus, req.params changes as it moves through the middleware pipeline, and you can’t guarantee that a property which existed in one middleware still exists in a later middleware.

Fortunately, there’s an easy way to avoid all of these little “gotchas” with req.params. The Parse Request middlweare also stores the parsed path parameters on the req.pathParams object. The req.pathParams object doesn’t have any special behavior. It’s just a normal property on the Request object. You don’t need to register any param callback functions. You don’t need to add redundant middleware to every nested router in your app. And the object will be the same in all of your middleware, regardless of how the middleware was registered or whether your Express parameters are named the same as your Swagger parameters.