An OpenApi validator for ExpressJS that automatically validates API requests and responses using an OpenAPI 3 specification.
express-openapi-validator is an unopinionated library that integrates with new and existing API applications. express-openapi-validator lets you write code the way you want; it does not impose any coding convention or project layout. Simply, install the validator onto your express app, point it to your OpenAPI 3 specification, then define and implement routes the way you prefer. See an example.
Features:
- ✔️ request validation
 - ✔️ response validation
 - 👮 security validation / custom security functions
 - 👽 3rd party / custom formats
 - ✂️ $ref support; split specs over multiple files
 - 🎈 file upload
 
npm i express-openapi-validator- Install the openapi validator
 
new OpenApiValidator({
  apiSpec: './test/resources/openapi.yaml',
  validateRequests: true, // (default)
  validateResponses: true, // false by default
}).install(app);- Register an error handler
 
app.use((err, req, res, next) => {
  // format error
  res.status(err.status || 500).json({
    message: err.message,
    errors: err.errors,
  });
});Note: Ensure express is configured with all relevant body parsers. body parser middleware functions must be specified prior to any validated routes. See an example.
See Advanced Usage options to:
- inline api specs as JSON.
 - configure request/response validation options
 - tweak the file upload configuration.
 - customize authentication with 
securityHandlers. - use OpenAPI 3.0.x 3rd party and custom formats.
 - and more...
 
The following demonstrates how to use express-openapi-validator to auto validate requests and responses. It also includes file upload!
See the complete source code for the example below:
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const logger = require('morgan');
const http = require('http');
const app = express();
// 1. Import the express-openapi-validator library
const OpenApiValidator = require('express-openapi-validator').OpenApiValidator;
// 2. Set up body parsers for the request body types you expect
//    Must be specified prior to endpoints in 5.
app.use(bodyParser.json());
app.use(bodyParser.text());
app.use(bodyParser.urlencoded());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// 3. (optionally) Serve the OpenAPI spec
app.use('/spec', express.static(spec));
// 4. Install the OpenApiValidator onto your express app
new OpenApiValidator({
  apiSpec: './openapi.yaml',
  // securityHandlers: { ... }, // <-- if using security
  // validateResponses: true, // <-- to validate responses
  // unknownFormats: ['my-format'] // <-- to provide custom formats
}).install(app);
// 5. Define routes using Express
app.get('/v1/pets', function(req, res, next) {
  res.json([{ id: 1, name: 'max' }, { id: 2, name: 'mini' }]);
});
app.post('/v1/pets', function(req, res, next) {
  res.json({ name: 'sparky' });
});
app.get('/v1/pets/:id', function(req, res, next) {
  res.json({ id: req.params.id, name: 'sparky' });
});
// 5a. Define route(s) to upload file(s)
app.post('/v1/pets/:id/photos', function(req, res, next) {
  // files are found in req.files
  // non-file multipart params can be found as such: req.body['my-param']
  res.json({
    files_metadata: req.files.map(f => ({
      originalname: f.originalname,
      encoding: f.encoding,
      mimetype: f.mimetype,
      // Buffer of file conents
      buffer: f.buffer,
    })),
  });
});
// 6. Create an Express error handler
app.use((err, req, res, next) => {
  // 7. Customize errors
  res.status(err.status || 500).json({
    message: err.message,
    errors: err.errors,
  });
});curl -s http://localhost:3000/v1/pets/as |jq
{
  "message": "request.params.id should be integer",
  "errors": [
    {
      "path": ".params.id",
      "message": "should be integer",
      "errorCode": "type.openapi.validation"
    }
  ]
} curl -s 'http://localhost:3000/v1/pets?limit=25' |jq
{
  "message": "request.query should have required property 'type', request.query.limit should be <= 20",
  "errors": [
    {
      "path": ".query.type",
      "message": "should have required property 'type'",
      "errorCode": "required.openapi.validation"
    },
    {
      "path": ".query.limit",
      "message": "should be <= 20",
      "errorCode": "maximum.openapi.validation"
    }
  ]
} curl -s --request POST \
  --url http://localhost:3000/v1/pets \
  --data '{}' |jq
{
  "message": "'X-API-Key' header required",
  "errors": [
    {
      "path": "/v1/pets",
      "message": "'X-API-Key' header required"
    }
  ]
}Providing the header passes OpenAPI validation.
Note: that your Express middleware or endpoint logic can then provide additional checks.
curl -XPOST http://localhost:3000/v1/pets \
  --header 'X-Api-Key: XXXXX' \
  --header 'content-type: application/json' \
  -d '{"name": "spot"}' | jq
{
  "id": 4,
  "name": "spot"
}curl -s --request POST \
  --url http://localhost:3000/v1/pets \
  --header 'content-type: application/xml' \
  --header 'x-api-key: XXXX' \
  --data '{
        "name": "test"
}' |jq
  "message": "unsupported media type application/xml",
  "errors": [
    {
      "path": "/v1/pets",
      "message": "unsupported media type application/xml"
    }
  ]
}curl -s --request POST \
  --url http://localhost:3000/v1/pets \
  --header 'content-type: application/json' \
  --header 'x-api-key: XXXX' \
  --data '{}'|jq
{
  "message": "request.body should have required property 'name'",
  "errors": [
    {
      "path": ".body.name",
      "message": "should have required property 'name'",
      "errorCode": "required.openapi.validation"
    }
  ]
}curl -XPOST http://localhost:3000/v1/pets/10/photos -F [email protected]|jq
{
  "files_metadata": [
    {
      "originalname": "app.js",
      "encoding": "7bit",
      "mimetype": "application/octet-stream"
    }
  ]
}Errors in response validation return 500, not of 400
/v1/pets/99 will return a response that does not match the spec
 curl -s 'http://localhost:3000/v1/pets/99' |jq
{
  "message": ".response should have required property 'name', .response should have required property 'id'",
  "errors": [
    {
      "path": ".response.name",
      "message": "should have required property 'name'",
      "errorCode": "required.openapi.validation"
    },
    {
      "path": ".response.id",
      "message": "should have required property 'id'",
      "errorCode": "required.openapi.validation"
    }
  ]
}
express-openapi validator provides a good deal of flexibility via its options.
Options are provided via the options object. Options take the following form:
new OpenApiValidator(options).install({
  apiSpec: './openapi.yaml',
  validateRequests: true,
  validateResponses: true,
  ignorePaths: /.*\/pets$/
  unknownFormats: ['phone-number', 'uuid'],
  multerOpts: { ... },
  securityHandlers: {
    ApiKeyAuth: (req, scopes, schema) => {
      throw { status: 401, message: 'sorry' }
    }
  }
});Specifies the path to an OpenAPI 3 specification or a JSON object representing the OpenAPI 3 specificiation
apiSpec: './path/to/my-openapi-spec.yaml'or
  apiSpec: {
  openapi: '3.0.1',
  info: {...},
  servers: [...],
  paths: {...},
  components: {
    responses: {...},
    schemas: {...}
  }
}Determines whether the validator should validate requests.
- 
true(default) - validate requests. - 
false- do not validate requests. - 
{ ... }- validate requests with optionsallowUnknownQueryParameters:
true- enables unknown/undeclared query parameters to pass validationfalse- (default) fail validation if an unknown query parameter is present
For example:
validateRequests: { allowUnknownQueryParameters: true }
 
Determines whether the validator should validate responses. Also accepts response validation options.
- 
true- validate responses in 'strict' mode i.e. responses MUST match the schema. - 
false(default) - do not validate responses - 
{ ... }- validate responses with optionsremoveAdditional:
"failing"- additional properties that fail schema validation are automatically removed from the response.
For example:
validateResponses: { removeAdditional: 'failing' }
 
Defines a regular expression that determines whether a path(s) should be ignored. Any path which matches the regular expression will not be validated.
The following ignores any path that ends in /pets
ignorePaths: /.*\/pets$/
Defines how the validator should behave if an unknown or custom format is encountered.
- 
true(default) - When an unknown format is encountered, the validator will report a 400 error. - 
[string](recommended for unknown formats) - An array of unknown format names that will be ignored by the validator. This option can be used to allow usage of third party schemas with format(s), but still fail if another unknown format is used.e.g.
unknownFormats: ['phone-number', 'uuid']
 - 
"ignore"- to log warning during schema compilation and always pass validation. This option is not recommended, as it allows to mistype format name and it won't be validated without any error message. 
Specifies the options to passthrough to multer. express-openapi-validator uses multer to handle file uploads. see multer opts
Determines whether the validator should coerce value types to match the type defined in the OpenAPI spec.
true(default) - coerce scalar data types.false- no type coercion."array"- in addition to coercions between scalar types, coerce scalar data to an array with one element and vice versa (as required by the schema).
Note:
securityHandlersare an optional component.securityHandlersprovide a convenience, whereby the request, declared scopes, and the security schema itself are provided as parameters to eachsecurityHandlerscallback that you define. The code you write in each callback can then perform authentication and authorization checks. Note that the same can be achieved using standard Express middleware. The difference is thatsecurityHandlersprovide you the OpenAPI schema data described in your specification_. Ulimately, this means, you don't have to duplicate that information in your code.
All in all,
securityHandlersare purely optional and are provided as a convenience.
Security handlers specify a set of custom security handlers to be used to validate security i.e. authentication and authorization. If a securityHandlers object is specified, a handler must be defined for all securities. If `securityHandlers are not specified, a default handler is always used. The default handler will validate against the OpenAPI spec, then call the next middleware.
If securityHandlers are specified, the validator will validate against the OpenAPI spec, then call the security handler providing it the Express request, the security scopes, and the security schema object.
- 
securityHandlersis an object that maps security keys to security handler functions. Each security key must correspond tosecuritySchemename. ThesecurityHandlersobject signature is as follows:{ securityHandlers: { [securityKey]: function( req: Express.Request, scopes: string[], schema: SecuritySchemeObject ): void, } }
For example:
securityHandlers: { ApiKeyAuth: function(req, scopes, schema) { console.log('apikey handler throws custom error', scopes, schema); throw Error('my message'); }, }
The express-openapi-validator performs a basic validation pass prior to delegating to security handlers. If basic validation passes, security handler function(s) are invoked.
In order to signal an auth failure, the security handler function must either:
throw { status: 403, message: 'forbidden' }throw Error('optional message')return false- return a promise which resolves to 
falsee.gPromise.resolve(false) - return a promise rejection e.g.
Promise.reject({ status: 401, message: 'yikes' });Promise.reject(Error('optional 'message')Promise.reject(false)
 
Note: error status
401is returned, unless optioni.above is usedSome examples:
securityHandlers: { ApiKeyAuth: (req, scopes, schema) => { throw Error('my message'); }, OpenID: async (req, scopes, schema) => { throw { status: 403, message: 'forbidden' } }, BasicAuth: (req, scopes, schema) => { return Promise.resolve(false); }, ... }
In order to grant authz, the handler function must either:
return true- return a promise which resolves to 
true 
Some examples
securityHandlers: { ApiKeyAuth: (req, scopes, schema) => { return true; }, BearerAuth: async (req, scopes, schema) => { return true; }, ... }
Each
securityHandlerssecurityKeymust match acomponents/securitySchemespropertycomponents: securitySchemes: ApiKeyAuth: # <-- Note this name must be used as the name handler function property type: apiKey in: header name: X-API-Key
See OpenAPI 3 authentication for
securitySchemeandsecuritydocumentationSee examples from unit tests
 
The validator will only validate requests — and (optionally) responses — that are under the server's base URL.
This is useful for those times when the API and frontend are being served by the same application. (More detail about the base URL.)
servers:
  - url: https://api.example.com/v1The validation applies to all paths defined under this base URL. Routes in your app that are not under the base URL—such as pages—will not be validated.
| URL | Validated? | 
|---|---|
https://api.example.com/v1/users | 
✅ | 
https://api.example.com/index.html | 
no; not under the base URL | 
Note that in some cases, it may be necessary to skip validation for paths under the base url. To do this, use the ignorePaths option.
Q: I can disallow unknown query parameters with allowUnknownQueryParameters: false. How can disallow unknown body parameters?
A: Add additionalProperties: false when describing e.g a requestBody to ensure that additional properties are not allowed. For example:
Pet:
additionalProperties: false
required:
  - name
properties:
  name:
    type: string
  type:
    type: stringQ: Can I use express-openapi-validator with swagger-ui-express?
A: Yes. Be sure to use the swagger-ui-express serve middleware prior to installing OpenApiValidator. This will ensure that swagger-ui-express is able to fully prepare the spec before before OpenApiValidator attempts to use it. For example:
const swaggerUi = require('swagger-ui-express')
const OpenApiValidator = require('express-openapi-validator').OpenApiValidator
...
app.use('/', swaggerUi.serve, swaggerUi.setup(documentation))
new OpenApiValidator({
  apiSpec, // api spec JSON object
  //... other options
  }
}).install(app)Contributions welcome! Here's how to contribute.
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!

