module:middleware/validate
- Description:
Validation and Rate Limiter Middleware
As oppose to the limiter by path this middleware validates first the params/query/body parameters and returns an error immediately, then if configured can check rate limits for the matching method, path and parameter behaving similar to the
module:api/limiter.For example this is useful and universally checked in case of multi-tenant environment when each tenant is distinguished by path/query/body property like accountId, clientId or else.
Validating common global parameters upfront with rate limits allows the actual business handlers to avoid boilerplate checks and focus only on specific logic instead and allows scaling and restrictions to be applied in real time without code changes.
Because the router does not validate params parts in the path, only extracts, this is a way to enforce path parameters to a particular type or format.
Validation config
middleware-validate-params,middleware-validate-query,middleware-validate-bodyconfig parameters are configured, only matched methods and paths are checked, each parameter will be validated usingmodule:lib/validate.Errors are returned immediately.
Validated and converted values are placed back into params/query/body, this allows subsequent middleware to reuse already validated and converted values immediately.
Path params are kept as strings.
Rate limiting
If rate limiting is required set the
rateand other parameters must be placed with rate prefix, likerate_interval, rate_ttl, rate_max, rate_queue...`, all valid parameters formodule:api/limitercan be placed in the config.The path rating logic is the same as in the limiter middleware.
Configurations with the same path and method(s) are merged into a single object, i.e. changes are accumulated, to clear values explicit values must be set like 0 or null.
To rate limit by session ID or authenticated user is supported if validation succeded:
rate_sessionrates the session id from the headerrate_userrates verified user id
By default this middleware is executed after the users middleware, i.e. user/session verification must succeed but still in case of missing session or user id the rating will use undefined, i.e. it will rate all requests without sessions globally.
NOTE: Named/wildcard parameters in the validate middleware paths must match the actual paths in the custom middleware to reuse the same validated parameters.
Examples
# Validate accountId for all /account requests and allow 100 req/s only middleware-validate-params-get,post-accountId-/account/:accountId/* = type:int,strict:true,min:100000,required:true,rate:100 # Validate clientId to be a number in the query for all /api requests and allow 100 req/s only middleware-validate-query-get,post-clientId-/api/* = type:int,max:32,required:true,rate:100,rate_interval:30000 # Validate login email and limit to 2 req per minute, increase delay middleware-validate-body-post-login-/login = type:email,max:128,required:true # Nerge with previous entry, add rate limiting to validation middleware-validate-body-post-login-/login = rate:2,rate_interval:60000,rate_multiplier:1.5 # Use JSON format for regexp validation or complex structures middleware-validate-body-post-ssn-/register = { "required": true, "regexp": "^[0-9]{3}-[0-9]{2}-[0-9]{4}$", "errmsg": "Valid SSN is required in NNN-NN-NNNN format" } # Rate limit all /admin/XXX requests by session id and XXX part to allow only 10 per 30s middleware-validate-params-*-0-/admin/* = rate:10,rate_interval:30000,rate_session:true # Rate limit all /admin/XXX requests by user and XXX part to allow only 10 per 30s middleware-validate-params-*-0-/admin/* = rate:10,rate_interval:30000,rate_user:trueGlobal mode
Enable via
middleware-validate-enable = trueto dynamically check every request path, this allows to add more or modify routes without restartingFixed config mode
To enable just what is in the config on start and ignore new routes, modifying existing routes is still supported
middleware-validate-enable = fixed
- Source:
Members
(static) args :Array.<ConfigOptions>
- Source:
- Default Value:
[ { "name": "enable", "descr": "Enable the middlware, 'true' means dynamicaly check all requests, 'fixed' means set routes from the config on start" }, { "name": "(query|body|params)-([a-z,*]+)-([a-zA-Z0-9_]+)-(/.+)", "type": "map", "no_camel": 1, "ephemeral": 1, "logger": "error", "onupdate": "", "descr": "Validate and optionally rate limit by a parameter from query/body/params by method and path", "example": "middleware-validate-query-*-accountId-/api/* = type:int,required:true,rate:10,rate_interval:30000" }, { "name": "reset", "type": "callback", "callback": "", "descr": "Reset all rules" }, { "name": "priority", "type": "int", "descr": "Add routes with this priority sorting number, for config mode only" } ]
Methods
(static) configureMiddleware()
- Description:
Start global middleware if enabled
- Source:
(static) handle(context, next)
- Source:
Parameters:
| Name | Type | Description |
|---|---|---|
context |
RequestContext | |
next |
function() |
Example
const { api, middleware } = require("backendjs");
const { validate } = middleware;
api.app.post("*", validate)
api.app.post("/account/*", validate)
api.app.post("/account", {
body: {
accountId: { type: "int", required: true, rate: 100 },
amount: { type: "number", max: 1000 }
}
}, handle: validate.handle })