From 7c16e5d8cbb3b140dbd533769e3436b5841987b8 Mon Sep 17 00:00:00 2001 From: Julien Gautier Date: Sun, 26 Apr 2026 22:07:55 +0200 Subject: [PATCH] =?UTF-8?q?docs(adr):=20add=20ADR=200012=20=E2=80=94=20exp?= =?UTF-8?q?ress-validator=20for=20input=20validation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...0012-input-validation-express-validator.md | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 docs/decisions/0012-input-validation-express-validator.md diff --git a/docs/decisions/0012-input-validation-express-validator.md b/docs/decisions/0012-input-validation-express-validator.md new file mode 100644 index 0000000..bdd5241 --- /dev/null +++ b/docs/decisions/0012-input-validation-express-validator.md @@ -0,0 +1,64 @@ +# Use express-validator for input validation at the route level + +* Status: accepted +* Date: 2026-04-26 + +## Context and Problem Statement + +API endpoints accepted user input without validating format, length, or type. A `fieldValidation` helper existed in several controllers but only checked for empty values, was duplicated across three controllers (users, articles, products), and had a critical bug: it called `next(error)` without `return`, so execution continued even when a field was invalid. + +## Decision Drivers + +* Input validation must happen before business logic and must halt execution on failure. +* Validation rules should be declared at the route level, not buried inside controller logic. +* The solution must be consistent and reusable across the codebase without adding a framework wrapper. + +## Considered Options + +* Keep and fix the `fieldValidation` helper +* Joi with a validation middleware wrapper +* express-validator with route-level chains + +## Decision Outcome + +Chosen option: "express-validator", because it integrates natively as Express middleware, allows validation rules to be declared directly in route definitions, and requires no wrapper function. A shared `validate.js` middleware reads `validationResult` and returns HTTP 422 with a structured error body if any rule fails. + +Structure: +- `src/middlewares/validate.js` — shared middleware that checks `validationResult` and short-circuits on errors +- `src/middlewares/validators/users.validators.js` — rule sets for user endpoints +- `src/middlewares/validators/articles.validators.js` — rule sets for article endpoints +- Rules applied at route level: `router.post('/', rules, validate, controller)` + +Initial coverage: CMS user endpoints (register, login, update profile/email/username/role) and article endpoints (create, update). Products and tags endpoints retain the old `fieldValidation` pattern pending a separate ecommerce validation pass. + +### Positive Consequences + +* Validation always runs before the controller — no risk of continuing on invalid input. +* Rules are co-located with routes, making the contract of each endpoint visible at a glance. +* Reusable rule sets can be composed and shared across routes. +* `fieldValidation` removed from users and articles controllers — no more duplicated logic. + +### Negative Consequences + +* Products and tags controllers still use the old `fieldValidation` pattern — inconsistency until the ecommerce pass is done. +* Validation rules must be maintained in sync with model constraints (e.g. if a column length changes, the validator must be updated manually). + +## Pros and Cons of the Options + +### Keep and fix fieldValidation + +* Good, because no new dependency. +* Bad, because it is duplicated in every controller that needs it. +* Bad, because it belongs in controllers, not at the boundary where input arrives. + +### Joi + +* Good, because schema-based validation with rich type coercion. +* Bad, because requires a wrapper middleware to integrate with Express — adds boilerplate not present in the existing codebase. + +### express-validator + +* Good, because native Express middleware — no wrapper needed. +* Good, because rule sets are plain arrays, easy to compose and test independently. +* Good, because actively maintained with wide adoption in Express projects. +* Bad, because rules are imperative chains rather than declarative schemas, which can be verbose for complex objects.