Dinner validation
Request Body Validation
Dinner uses the OpenAPI schema under requestBody as the contract for req.body.
If the JSON body does not match, the request stops with a 400 response before the controller action runs.
The YAML Dinner Reads
Validation starts at the operation's JSON body schema. Dinner resolves that schema, converts it for Ajv,
compiles it once for the route, and runs it against req.body.
requestBody:
required: true
content:
application/json:
schema:
type: objectrequestBody Marks the operation as accepting a body.
application/json Provides the schema Dinner uses for JSON payloads.
schema Defines the Ajv validation contract for req.body.
Inline Request Body Schema
For small routes or examples, put the schema directly under schema.
This object is the shape Ajv checks before Dinner calls the controller.
# server/openapi/users.yaml
paths:
/users:
post:
x-controller: user.controller
x-action: create
summary: Create a user
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- email
- password
properties:
email:
type: string
format: email
password:
type: string
minLength: 8
additionalProperties: false
responses:
'201':
description: CreatedReference a Named Schema
In real routes, keep the operation focused on routing and point schema at a named entry under components.schemas.
Dinner resolves the reference, then Ajv validates req.body against the resolved schema.
Route references the schema
# server/openapi/users.yaml
paths:
/users:
post:
x-controller: user.controller
x-action: create
summary: Create a user
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
responses:
'201':
description: CreatedComponents define the schema
# server/openapi/components.yaml
components:
schemas:
CreateUserRequest:
type: object
required:
- email
- password
properties:
email:
type: string
format: email
password:
type: string
minLength: 8
additionalProperties: falseThe $ref value points to the schema name in components.schemas.
It is not the body being validated; it is the schema Dinner gives to Ajv.
If the route and components live in different files, load them through Stitch so Dinner receives one OpenAPI document.
Controller Contract
Controllers should treat schema validation as transport validation. Keep business rules in your application logic, but do not duplicate basic required-field, type, format, and range checks in every action.
// server/controller/user.controller.ts
import { Component } from "@noego/ioc";
@Component()
export default class UserController {
async create({ body }: { body: { email: string; password: string } }) {
// Dinner already rejected malformed bodies before this method runs.
return {
created: true,
email: body.email
};
}
}Useful Schema Rules
required Reject bodies missing fields the controller depends on.
additionalProperties: false Reject unknown keys instead of silently accepting loose payloads.
format Validate strings such as email or uri when ajv_formats is enabled.
minLength / maximum Keep simple boundary checks in the API contract.
enum Constrain fixed values such as status or sort direction.
pattern Apply regex checks for fields that have a known text shape.
Invalid Body Response
When Ajv rejects the body, Dinner responds with the route, method, and schema that failed. The controller is not called.
{
"error": true,
"message": "Invalid request body",
"requirements": {
"type": "object",
"required": ["email", "password"],
"properties": {
"email": { "type": "string", "format": "email" },
"password": { "type": "string", "minLength": 8 }
},
"additionalProperties": false
},
"validation_schema": {
"type": "object",
"required": ["email", "password"]
},
"path": "/users",
"method": "post",
"statusCode": 400
}Path Constraints Are Route Matching
Request body validation uses Ajv schemas. Path constraints decide whether a URL matches a route before body validation is relevant.
Use the Dinner routes guide for path tokens, route regex, case-sensitive matching, optional segments, splats, and extracted req.params.
Manual Dinner Server Setup
This setup is for manual or standalone @noego/dinner usage. In an @noego/app project, App owns Dinner bootstrapping through bootBackend().
Add JSON parsing before Dinner handles routes. Enable ajv_formats when schemas use string formats such as email.
import express from "express";
import { Server } from "@noego/dinner";
const app = express();
app.use(express.json());
// Manual/standalone Dinner setup only. @noego/app already wires this pattern for app projects.
await Server.createServer({
server: app,
openapi: "server/openapi.yaml",
controllers_base_path: "server/controller",
controller_args_provider: async (req, res) => ({
body: req.body,
params: req.params,
query: req.query,
req,
res
}),
controller_builder: async (Controller) => new Controller(),
ajv_formats: true
});