The "Double Work" Problem
As Express developers, weβve all been there. You spend an hour perfecting your validation logic for a new endpoint:
- You check for required fields.
- You validate email formats.
- You set minimum string lengths.
Then, you have to do it all over again in a Swagger file or a Postman collection so your frontend team knows how to use the API. If you change a field in the code and forget to update the docs, things break, and Slack messages start flying.
I got tired of this manual sync, so I built expressjs-field-validator.
What is expressjs-field-validator?
Itβs a lightweight middleware designed to be the "single source of truth" for your request validation and your API documentation.
Key Features:
- Schema-based Validation: Define rules in a clean object.
- Automatic Doc Generation: It reads your schemas and generates documentation for you.
- Zero Bloat: Minimal dependencies to keep your project fast.
See it in Action
const express = require('express');
const {
validateBody,
validateParam,
validateQuery,
validateHeader,
param,
checkService,
generateDocs,
documentResponse,
} = require('expressjs-field-validator');
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
// βββ 1. Basic required field validation ββββββββββββββββββββββββββββββββββββββ
// POST /users { "name": "John", "email": "john@example.com" }
app.post('/users',
validateBody().isToBeRejected().sendErrorCode(422).addParams([
param('name').isRequired(),
param('email').isRequired().isEmail(),
]),
documentResponse({
201: {
description: 'User created successfully',
body: { message: 'User created', data: { id: 1, name: 'John', email: 'john@example.com' } }
},
422: {
description: 'Validation failed',
body: { error: 'email is required' }
}
}),
(req, res) => {
res.status(201).send({ message: 'User created', data: req.body });
}
);
// βββ 2. Number, range, and length validation βββββββββββββββββββββββββββββββββ
// POST /products { "title": "Widget", "price": 25, "sku": "AB123" }
app.post('/products',
validateBody().isToBeRejected().sendErrorCode(422).debug(true).addParams([
param('title').isRequired().minimumLength(3).maximumLength(100),
param('price').isRequired().isNumber().minimumNumber(1).maximumNumber(99999),
param('sku').isRequired().minimumLength(3).maximumLength(20),
]),
documentResponse({
201: {
description: 'Product created',
body: { message: 'Product created', data: { title: 'Widget', price: 25, sku: 'AB123' } },
headers: { 'X-Product-Id': '12345' }
},
422: {
description: 'Validation error',
body: { error: 'price must be between 1 and 99999' }
}
}),
(req, res) => {
res.status(201).send({ message: 'Product created', data: req.body });
}
);
// βββ 3. Boolean, date, includes/excludes, and convertToFormat ββββββββββββββββ
// POST /events { "title": "Meetup", "date": "15/03/2026", "type": "online", "isPublic": true }
// β date is validated as DD/MM/YYYY then converted to YYYY-MM-DD for storage
app.post('/events',
validateBody().isToBeRejected().addParams([
param('title').isRequired(),
param('date').isRequired().isDate().dateFormat('DD/MM/YYYY').convertToFormat('YYYY-MM-DD'),
param('type').isRequired().shouldInclude(['online', 'offline', 'hybrid']),
param('isPublic').isBoolean(),
]),
(req, res) => {
// req.body.date is now in YYYY-MM-DD format
res.status(201).send({ message: 'Event created', data: req.body });
}
);
// βββ Start server ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const PORT = 3000;
// βββ Generate API documentation ββββββββββββββββββββββββββββββββββββββββββββββ
// This must be called AFTER all routes are registered
generateDocs(app, {
title: 'Example API',
version: '1.0.0',
outputDir: './docs',
filename: 'api-docs.html'
});
app.listen(PORT, (err) => {
if (err) {
console.error(`Error starting server: ${err}`);
return;
}
console.log(`Server is listening on http://localhost:${PORT}`);
console.log(`API Docs available at: ./docs/api-docs.html`);
});
Why I Open Sourced This
I wanted a tool that didn't require a 200-page manual to understand. This package is built for developers who want to move fast without sacrificing code quality or documentation.
What is next
- More export formats (OpenAPI 3.0, Postman Collections, etc.).
- More field validators like address, credit card etc.
Contributing & Feedback
This is an evolving project, and Iβd love the communityβs input.
Check it out on NPM: expressjs-field-validator
Contribute on GitHub: https://github.com/gsmithun4/expressjs-field-validator
Top comments (0)