An OpenApi validator for ExpressJS that automatically validates API requests using an OpenAPI 3 specification.
express-openapi-validator is unopinionated and does not impose any coding convention or project structure. 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.
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);
Note: response validation is currently a beta feature
Then, register an error handler to report and customize errors
app.use((err, req, res, next) => {
// format error
res.status(err.status || 500).json({
message: err.message,
errors: err.errors,
});
});
The apiSpec
option may be specified as the spec object itself, rather than a path e.g.
const apiSpec = {
openapi: "3.0.1",
info: {...},
servers: [...],
paths: {...},
components: {
responses: {...},
schemas: {...}
}
}
new OpenApiValidator({ apiSpec }).install(app);
new OpenApiValidator(options).install(app);
apiSpec:
a string value specifying the path to the OpenAPI 3.0.x spec or a JSON object representing an OpenAPI spec.
validateRequests:
enable response validation.
- true - (default) validate requests.
- false - do not validate requests.
validateResponses:
enable response validation.
- true - validate responses
- false - (default) do not validate responses
coerceTypes:
change data type of data to match type keyword. See the example in Coercing data types and coercion rules. Option values:
- 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).
multerOpts:
the multer opts to passthrough to multer
Try the complete example below: (it includes file upload as well!)
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;
app.use(bodyParser.json());
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')));
// 2. (optionally) Serve the OpenAPI spec
app.use('/spec', express.static(spec));
// 3. Install the OpenApiValidator onto your express app
new OpenApiValidator({
apiSpec: './openapi.yaml',
}).install(app);
// 4. 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' });
});
// 4. 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,
})),
});
});
// 5. Create an Express error handler
app.use((err, req, res, next) => {
// 6. Customize errors
res.status(err.status).json({
message: err.message,
errors: err.errors,
});
});
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/v1
The 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 |
Example Express API Server (clone it)
A fully working example lives here
/pets/:id
should be of type integer, express-openapi-validator returns:
curl -s http://localhost:3000/v1/pets/as |jq
{
"errors": [
{
"path": ".params.id",
"message": "should be integer",
"errorCode": "type.openapi.validation"
}
]
}
/pets?limit=1
should be of type integer with a value greater than 5. It should also require an additional query paramter, test
, express-openapi-validator returns:
curl -s http://localhost:3000/v1/pets?limit=1 |jq
{
"errors": [
{
"path": ".query.limit",
"message": "should be >= 5",
"errorCode": "minimum.openapi.validation"
},
{
"path": ".query.test",
"message": "should have required property 'test'",
"errorCode": "required.openapi.validation"
}
]
}
POST /pets
is defined to only accept media type application/json, express-openapi-validator returns:
curl -s --request POST \
--url http://localhost:3000/v1/pets \
--header 'content-type: application/xml' \
--data '{
"name": "test"
}' |jq
{
"errors": [
{
"path": "/v1/pets",
"message": "unsupported media type application/xml"
}
]
}
POST /pets
request body is required to contain the name
properly, express-openapi-validator returns:
curl -s --request POST \
--url http://localhost:3000/v1/pets \
--header 'content-type: application/json' \
--data '{}' |jq
{
"errors": [
{
"path": ".query.name",
"message": "should have required property 'name'",
"errorCode": "required.openapi.validation"
}
]
}
curl -s -XPOST http://localhost:3000/v1/pets/10/photos -F fileZZ=@app.js | jq
{
"errors": [
{
"path": "file",
"message": "should have required property 'file'",
"errorCode": "required.openapi.validation"
}
]
}
Thanks goes to these wonderful people (emoji key):
Carmine DiMascio 💻 |
Sheldhur Mornor 💻 |
Andrey Trebler 💻 |
This project follows the all-contributors specification. Contributions of any kind welcome!