Scaffolding
Use accorudo model add and accorudo route add to grow a bundle file by file. The commands create missing directories, append types in the right place, and register new routes in api.ts.
Hand-writing contracts is always valid. Scaffolding is for speed and consistency when you already know the shape.
Field specs
Both commands accept repeatable field specs:
name:type[@modifier[@modifier...]]
| Example | Meaning |
|---|---|
name:string | Required string property |
limit?:number | Optional number property |
id:number@integer:int64 | Number with @openapi.type integer and @openapi.format int64 |
description?:string@nullable | Optional nullable string |
id:string@format=uuid | String with UUID format |
status:string@enum=draft,published | String enum |
Modifiers map directly to OpenAPI annotations.
Add a model
accorudo model add WidgetAttributes \
--bundle contracts/main \
--component \
--field id:number@integer:int64 \
--field name:string \
--field "description?:string@nullable"
Writes to models/widget.ts (domain derived from the type name) unless you override it:
| Flag | Description |
|---|---|
-b, --bundle <dir> | Bundle directory (default: contracts/main) |
-d, --domain <name> | File stem under models/ (default: derived from type name) |
--component | Add @openapi.component |
--type <expression> | Custom TypeScript type (alternative to --field) |
--field <spec> | Object property (repeatable) |
--dry-run | Print generated type without writing |
Use --field for object shapes the CLI builds for you. Use --type when you need full control: generics, unions, utility types, or project-specific wrappers:
accorudo model add WidgetEntity \
--component \
--type 'Entity<"widget", WidgetAttributes>'
Referenced types are imported automatically from models/ and types/ in the bundle. Quote the expression for the shell. Prefer single quotes when it contains double-quoted string literals.
Generated output:
/**
* @openapi.component
*/
export type WidgetAttributes = {
/**
* @openapi.type integer
* @openapi.format int64
*/
id: number;
name: string;
/** @openapi.nullable */
description?: string | null;
};
With --type:
/**
* @openapi.component
*/
export type WidgetEntity = Entity<"widget", WidgetAttributes>;
Add a route
accorudo route add listWidgets \
--method get \
--path /widget \
--tag widget \
--summary "List widgets" \
--query limit?:number \
--query offset?:number \
--query name?:string \
--response 'CollectionSuccess<WidgetEntity>'
Creates or updates routes/widget.ts and registers listWidgets in api.ts. Response and body types are imported automatically from models/ and types/.
| Flag | Description |
|---|---|
<key> | Registry key in camelCase (e.g. listWidgets) |
-m, --method | HTTP method |
-p, --path | Path with :params (e.g. /widget/:id) |
-t, --tag | Tag and routes file name |
-r, --response | Primary response type |
-b, --bundle <dir> | Bundle directory |
--summary <text> | OpenAPI summary |
--operation-id <id> | OpenAPI operationId (default: registry key) |
--query <spec> | Query parameter field (repeatable) |
--param <spec> | Path parameter override (repeatable; :id defaults to string) |
--body <type> | Existing request body type |
--body-field <spec> | Inline request body fields (repeatable) |
--on <status:type> | Extra response, e.g. 404:NotFoundResponse |
--status <code> | Primary response status (default: 200) |
--multipart | Emit MultipartRoute |
--security <name> | Security scheme (repeatable) |
--import <path:Types> | Override auto-import with an explicit path (repeatable) |
--dry-run | Preview generated files |
Types referenced in --response, --body, and --on are resolved automatically by scanning models/ and types/ in the bundle. Use --import only when you need to override the default path.
Path parameters
:params in --path become typed path params automatically:
accorudo route add getWidget \
--method get \
--path /widget/:id \
--tag widget \
--param id:string@format=uuid \
--response 'Success<WidgetEntity>' \
--on 404:NotFoundResponse
Adds WidgetByIdRouteFragment, GetWidgetRoute, and a registry entry. Success, WidgetEntity, and NotFoundResponse are imported from scanned model files.
Request body
Reference an existing type:
accorudo route add createWidget \
--method post \
--path /widget \
--tag widget \
--body CreateWidgetRequestBody \
--status 201 \
--response 'Success<WidgetEntity>'
Or define the body inline:
accorudo route add createWidget \
--method post \
--path /widget \
--tag widget \
--body-field name:string \
--body-field enabled:boolean \
--status 201 \
--response 'Success<WidgetEntity>'
Typical flow
accorudo init
accorudo model add WidgetAttributes --component \
--field id:number@integer:int64 \
--field name:string
accorudo model add WidgetEntity --component \
--field type:widget@enum=widget \
--field attributes:WidgetAttributes
accorudo route add listWidgets --method get --path /widget --tag widget \
--response 'CollectionSuccess<WidgetEntity>'
accorudo export contracts/main --out openapi/main.yaml
Use --dry-run on any command to inspect output before files are written.
See CLI overview for install, init, and sync.