OpenAPI Validator Middleware
This package, `openapi-validator-middleware`, provides robust input validation for HTTP requests within Node.js frameworks such as Express, Koa, and Fastify. It leverages your existing OpenAPI (formerly Swagger) 2.0 or 3.0 definition files to automatically validate request bodies, headers, path parameters, and query parameters, using the powerful AJV library under the hood. The current stable version is 3.2.6, with the last significant update in February 2022. This suggests a maintenance-focused release cadence rather than active feature development, as over four years have passed since its last update. A key differentiator is its multi-framework support and its reliance on standardized OpenAPI definitions for validation logic, offering a consistent approach to API input schema enforcement. It was notably renamed from `express-ajv-swagger-validation` starting with version 2.0.0, which was a breaking change primarily affecting package naming and import paths for existing users.
Common errors
-
InputValidationError: Request validation failed
cause An incoming HTTP request body, query parameters, path parameters, or headers do not conform to the defined OpenAPI schema.fixExamine the `err.errors` array in the `InputValidationError` object within your error handling middleware to identify specific validation failures. Adjust the client request or OpenAPI schema accordingly. -
Cannot find module 'uri-js'
cause The `uri-js` package, a required peer dependency for OpenAPI schema validation, is not installed in the project.fixInstall the missing peer dependency: `npm install uri-js`. -
Error: Failed to load OpenAPI definition from ...
cause The `init` or `initAsync` function was called with an incorrect or inaccessible path to the OpenAPI definition file, or the file itself is malformed/invalid.fixVerify that the `pathToSwaggerFile` argument points to a valid, readable YAML or JSON OpenAPI specification file. Check file permissions and ensure the file content is syntactically correct. -
Route handler not validating requests as expected.
cause The `validate()` middleware is not correctly matching the incoming request path to a defined path in the OpenAPI specification, potentially due to dynamic path parameters or middleware order.fixEnsure `req.route.path` (for Express) is correctly set by using `validator.validate()` within specific route definitions, rather than globally. For dynamic paths, ensure the OpenAPI path template matches the framework's route definition. Upgrading to `>=3.2.6` can fix issues with empty path parameters for child resources.
Warnings
- breaking The package was renamed from `express-ajv-swagger-validation` to `openapi-validator-middleware` in version 2.0.0. Existing users must update package names and import paths.
- gotcha The initialization functions come in synchronous (`init`) and asynchronous (`initAsync`) variants. `init` will block the event loop, while `initAsync` returns a Promise. For robust application startup, especially when loading potentially large OpenAPI definition files, `initAsync` is recommended.
- gotcha Validation of `multipart/form-data` requests has specific considerations. The middleware typically processes JSON or URL-encoded bodies. For file uploads or complex multipart data, additional parsing middleware (e.g., `multer` for Express) is required *before* `openapi-validator-middleware` to make the data available for validation.
- security Multiple security vulnerabilities have been addressed in various versions, including fixes for vulnerable packages in dependencies and general security enhancements. It is crucial to stay updated to mitigate known risks.
- gotcha The package lists `uri-js` as a peer dependency. If `uri-js` is not installed in your project, you may encounter errors related to URI validation or missing modules at runtime.
Install
-
npm install openapi-validator-middleware -
yarn add openapi-validator-middleware -
pnpm add openapi-validator-middleware
Imports
- validator object (default export)
import { init, validate } from 'openapi-validator-middleware';import validator from 'openapi-validator-middleware';
- validator (CommonJS require)
const { validate } = require('openapi-validator-middleware');const validator = require('openapi-validator-middleware'); - InputValidationError
import { InputValidationError } from 'openapi-validator-middleware';import validator from 'openapi-validator-middleware'; const { InputValidationError } = validator;
Quickstart
import express from 'express';
import path from 'path';
import validator from 'openapi-validator-middleware';
const app = express();
const PORT = process.env.PORT || 3000;
// Dummy OpenAPI spec for demonstration
const swaggerSpecPath = path.resolve('./swagger.yaml');
// In a real app, this would be a real file:
// fs.writeFileSync(swaggerSpecPath, `
// openapi: 3.0.0
// info:
// title: Test API
// version: 1.0.0
// paths:
// /users:
// post:
// requestBody:
// required: true
// content:
// application/json:
// schema:
// type: object
// properties:
// name:
// type: string
// email:
// type: string
// format: email
// required:
// - name
// - email
// responses:
// '200':
// description: User created
// `);
// In a real application, ensure the OpenAPI file exists.
// For this example, we'll initialize without reading a file directly
// to focus on the middleware usage, but you'd normally point to your spec.
// For simplicity, we'll manually define a schema here.
// In a real scenario, you would initialize with a path to your spec file:
// validator.init(swaggerSpecPath, { source: 'fs' });
// Simulate initialization with an in-memory spec if no file is present
// For a real setup, provide a path to your YAML/JSON OpenAPI spec.
const inMemorySpec = {
openapi: '3.0.0',
info: { title: 'Test API', version: '1.0.0' },
paths: {
'/users': {
post: {
requestBody: {
required: true,
content: {
'application/json': {
schema: {
type: 'object',
properties: {
name: { type: 'string' },
email: { type: 'string', format: 'email' }
},
required: ['name', 'email']
}
}
}
},
responses: { '200': { description: 'User created' } }
}
}
}
};
// NOTE: In a real scenario, you'd call validator.init(pathToSwaggerFile)
// We simulate by directly setting the internal schema for demonstration.
// This part is for demonstration only, the library expects a file path.
console.warn('Initializing openapi-validator-middleware without a physical file for demo. Provide a path to your spec in a real app.');
// A more realistic init would be:
// try {
// await validator.initAsync(swaggerSpecPath);
// } catch (error) {
// console.error('Failed to initialize validator:', error.message);
// process.exit(1);
// }
// This requires manually mocking the internal state, not directly possible via public API.
// So, for a runnable quickstart, we need an actual OpenAPI file.
// Let's create a minimal one for the example.
const fs = require('fs');
const swaggerContent = `
openapi: 3.0.0
info:
title: Test API
version: 1.0.0
paths:
/users:
post:
summary: Create a new user
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
minLength: 3
email:
type: string
format: email
required:
- name
- email
responses:
'201':
description: User created successfully
'400':
description: Invalid input
`;
fs.writeFileSync(swaggerSpecPath, swaggerContent);
validator.init(swaggerSpecPath);
app.use(express.json()); // Body parser middleware
app.post('/users', validator.validate(), (req, res) => {
// If validation passes, process the request
res.status(201).json({ message: 'User created', data: req.body });
});
// Error handling middleware for validation errors
app.use((err, req, res, next) => {
if (err instanceof validator.InputValidationError) {
return res.status(400).json({
message: 'Validation Error',
errors: err.errors,
validationContext: err.validationContext
});
}
next(err);
});
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
console.log(`Test with: curl -X POST -H "Content-Type: application/json" -d '{"name": "John Doe", "email": "john@example.com"}' http://localhost:${PORT}/users`);
console.log(`Test validation failure with: curl -X POST -H "Content-Type: application/json" -d '{"name": "Jo", "email": "invalid-email"}' http://localhost:${PORT}/users`);
});