Validazione delle richieste
Come funziona la validazione dipende dallo stack, e la differenza è importante:
- Express: la validazione è esplicita. Colleghi catene di
express-validator a un metodo tramite
_<verb>Validation. Gli schemiswaggerModelguidano documentazione e generazione dei tipi, non la validazione: dichiarare uno schema non valida la richiesta. - Bun/Elysia: la validazione è guidata dagli schemi. Gli schemi TypeBox che
metti su
body/query/paramsdi una rotta vengono compilati e applicati automaticamente da Elysia.
Un equivoco comune: sullo stack Express, swaggerModel / Magic Types descrivono l'API
per OpenAPI e i tipi generati. Non controllano le richieste in arrivo. Se devi
rifiutare input errati, dichiara una catena _<verb>Validation.
Express
Dichiarare la validazione
Aggiungi un array _<verb>Validation al servizio. Ogni elemento è una catena
express-validator. Efesto le esegue prima del tuo handler:
import { BaseApiService } from "efesto";
import { body, query, param } from "express-validator";
class Users extends BaseApiService {
constructor() {
super(__filename);
}
_getValidation = [
query("page").optional().isInt({ min: 1 }),
query("limit").optional().isInt({ min: 1, max: 100 }),
];
async _get(req, res) {
return res.json(await listUsers(req.query));
}
_postValidation = [
body("name").isString().isLength({ min: 2, max: 50 }),
body("email").isEmail(),
body("age").optional().isInt({ min: 0, max: 150 }),
];
async _post(req, res) {
return res.status(201).json(await createUser(req.body));
}
}
export default Users;
Gli array di validazione esistono per ogni verbo: _getValidation, _postValidation,
_putValidation, _patchValidation, _deleteValidation, _headValidation,
_optionsValidation, _traceValidation, _connectValidation.
Gestire gli errori di validazione
Efesto non impone una forma per gli errori. I risultati di express-validator sono
disponibili tramite validationResult(req); formattali nel tuo errorMiddleware (il
secondo hook passato a efesto()), che viene eseguito dopo le catene di validazione:
import { validationResult } from "express-validator";
const errorMiddleware = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
next();
};
Validazione personalizzata e tra campi
Tutto ciò che express-validator può fare funziona qui, perché queste sono catene express-validator. Per esempio, una regola asincrona personalizzata e un controllo tra campi:
_postValidation = [
body("email").isEmail().custom(async (email) => {
if (await emailExists(email)) throw new Error("Email already in use");
return true;
}),
body("confirmPassword").custom((value, { req }) => {
if (value !== req.body.password) throw new Error("Passwords do not match");
return true;
}),
];
Consulta la documentazione di express-validator
per l'API completa (sanitizer, oneOf, sintassi a schema e altro).
Bun/Elysia
Sullo stack Elysia, la validazione è lo schema. Collega schemi TypeBox a body,
query o params di una rotta; Elysia li compila, valida ogni richiesta e restituisce
un 422 con un errore descrittivo quando una richiesta non corrisponde. Lo stesso
schema documenta anche l'endpoint e tipizza l'handler.
- Class-based (BaseApiService)
- Native Elysia
import { BaseApiService, type Context, RouteValidation, t } from "efesto/elysia";
export default class extends BaseApiService {
_postValidation: RouteValidation = {
body: t.Object({
name: t.String({ minLength: 2, maxLength: 50 }),
email: t.String({ format: "email" }),
age: t.Optional(t.Number({ minimum: 0, maximum: 150 })),
}),
query: t.Object({ ref: t.Optional(t.String()) }),
};
_post({ body }: Context) {
return createUser(body); // validato rispetto allo schema
}
}
import { Elysia, t } from "efesto/elysia";
export default new Elysia().post("/", ({ body }) => createUser(body), {
body: t.Object({
name: t.String({ minLength: 2, maxLength: 50 }),
email: t.String({ format: "email" }),
age: t.Optional(t.Number({ minimum: 0, maximum: 150 })),
}),
});
TypeBox copre i vincoli a cui ricorreresti: minLength/maxLength,
minimum/maximum, format, pattern, enum (via t.Union/t.Literal), array e
oggetti annidati. Vedi la
guida alla validazione di Elysia.
Campi file
- Express: valida i campi non-file con
_<verb>Validationcome al solito; abilita l'upload con il flag_<verb>Multer(vedi Upload di file). Il file stesso (req.file) viene controllato nel tuo handler. - Elysia (nativo): descrivi un campo file con
t.File()nello schema del corpo; Elysia valida tipo e dimensione dallo schema. - Elysia (classe): abilita
_<verb>Multer/_<verb>MultipleMulter; il file arriva inctx.body(vedi Upload di file).