Robust Microservice Input Handling with Moleculer's AJV Validation
Learn how Moleculer's built‑in AJV validation centralizes input checks, reduces boilerplate, and catches errors early in microservice architectures.
22 Nov 2025, 20:54 UTC

Opening Problem and Takeaway
When a microservice receives an HTTP request, the first line of defense is input validation. Without it, a malformed payload can cause runtime errors, data corruption, or security issues that are hard to trace. The useful takeaway is that Moleculer provides built‑in declarative validation through AJV, letting you catch invalid data before it reaches your handler code.
Why Validation Matters in Microservices
In a distributed system, each service operates independently. If one service trusts incoming data blindly, a single bad request can cascade failures across the architecture. Validation enforces a contract:
- Type safety – ensures numbers are numbers, strings are strings, etc.
- Required fields – prevents missing keys that would break business logic.
- Default values – supplies sensible fallbacks, reducing optional‑parameter boilerplate.
These checks happen automatically, so you spend less time writing repetitive validation code and more time focusing on core business rules.
Moleculer's Declarative Validation Feature
Moleculer actions support a params schema that is processed by AJV (Another JSON Validator). The validation hook runs in the action lifecycle before the handler is invoked. If the payload does not match the schema, Moleculer returns a standardized 400 response containing AJV‑generated error details.
Key benefits:
- Centralized sanitization – the same schema is used for all actions in a service.
- Automatic error formatting – clients receive clear, machine‑readable messages.
- Version‑stable behavior – as long as the AJV version is consistent, validation outcomes stay predictable.
Worked Example
Below is a minimal service definition that validates a createUser action.
// service.js
const { ServiceFactory } = require('moleculer');
module.exports = ServiceFactory.moleculer({
name: 'user',
actions: {
createUser: {
params: {
$ref: 'user.schema.json' // reference external schema
},
handler(ctx) {
// ctx.params is already validated
const { username, age } = ctx.params;
// business logic here
return { id: '123', username, age };
}
}
}
});
// user.schema.json
{
"type": "object",
"required": ["username", "age"],
"properties": {
"username": { "type": "string", "minLength": 3 },
"age": { "type": "integer", "minimum": 13 }
},
"additionalProperties": false
}
If a client sends { "username": "ab", "age": "twenty" }, AJV will reject the request with a 400 error that lists the mismatched fields and reasons.
Trade‑off and Limitation
While AJV validation is powerful, complex nested payloads can cause the schema to become verbose, making it harder to maintain. Additionally, using different AJV versions in separate Moleculer plugins may lead to runtime validation errors because the underlying validation rules change between major releases. To mitigate this, keep all services on the same Moleculer major version and consider extracting large schemas into reusable files.
Verification Steps
- Inspect the schema – locate the
paramsdefinition in your service file or referenced schema. - Send a test request with a mismatched payload (e.g., wrong type, missing required field). Use a tool like
curlor Postman. - Check the response – Moleculer should return HTTP 400 with a JSON body containing AJV details such as
"errors": [{"instancePath": "/age", "message": "must be numeric"}]. - Confirm version consistency – run
moleculer --versionon each service instance. Ensure they all run the same major version (e.g., v1.x).
Actionable Closing
To adopt Moleculer’s validation feature:
- Define a JSON schema for each action’s parameters, either inline or in a separate file.
- Reference the schema in the action definition using
$refto keep definitions DRY. - Run a quick test request with an invalid payload and verify the 400 error includes AJV details.
- Maintain a single Moleculer major version across your services to avoid version‑related validation surprises.
By following these steps, you gain early input validation, reduced boilerplate, and more reliable microservice communication.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.