darto_zard_openapi 1.0.0
darto_zard_openapi: ^1.0.0 copied to clipboard
Hono-style zod-openapi for Darto — define a zard schema once to validate requests and generate the OpenAPI 3.1 document, with OpenAPIDarto, createRoute and Scalar UI.
darto_zard_openapi #
Hono-style zod-openapi
for Darto, powered by
zard.
Define a zard schema once and use it as the single source of truth: it
validates the request (real zard — email, refine, z.coerce.*, custom
messages) and generates the OpenAPI 3.1 document. One import, contract
decoupled from the handler, Scalar UI included.
Quick start #
import 'package:darto/darto.dart';
import 'package:darto_zard_openapi/darto_zard_openapi.dart';
// Define the schema once. .openapi(example:, description:) adds doc metadata per
// field — `example` is type-checked against the field's type. .openapiSchema('User')
// registers a reusable component (#/components/schemas/User).
final userSchema = z.map({
'name': z.string().min(1).openapi(example: 'Ada Lovelace', description: 'Full name'),
'email': z.string().email().openapi(description: 'Contact e-mail'),
'age': z.int().min(0).max(150).openapi(example: 28),
}).openapiSchema('User');
final userIdParam = z.map({
'id': z.coerce.int().min(1).openapi(description: 'User id'),
}).openapiSchema();
void main() async {
final app = Darto(); // your own Darto app
final api = OpenAPIDarto(app); // plug OpenAPI on top (composition)
// Reusable route contract (≈ createRoute), decoupled from the handler.
final getUser = createRoute(
method: 'get',
path: '/users/:id',
summary: 'Get a user by id',
request: Req(params: userIdParam),
responses: [
Res(200, 'User found', body: userSchema),
Res(404, 'User not found'),
],
);
// Attach contract + middlewares + handler (≈ app.openapi).
api.openapi(getUser, [], (c) {
final id = c.req.valid<Map<String, dynamic>>('param')['id']; // int, validated
if (id != 123) return c.status(404).json({'message': 'Not Found'});
return c.ok({'id': 123, 'name': 'Ada Lovelace', 'age': 28});
});
api.doc('/openapi.json', info: Info(title: 'Users API', version: '1.0.0'));
app.get('/docs', [], scalarUI(url: '/openapi.json')); // plain Darto route
await app.listen(3000);
}
How it maps to @hono/zod-openapi #
@hono/zod-openapi |
darto_zard_openapi |
|---|---|
new OpenAPIHono() |
OpenAPIDarto(Darto()) (composition) |
createRoute({...}) |
createRoute(...) |
app.openapi(route, handler) |
api.openapi(route, [middlewares], handler) |
field.openapi({example, description}) |
field.openapi(example:, description:) (type-safe example) |
schema.openapi('User') |
schema.openapiSchema('User') |
c.req.valid('param') |
c.req.valid<...>('param') |
app.doc('/openapi.json', {...}) |
api.doc('/openapi.json', info:, servers:) |
swaggerUI({url}) |
scalarUI(url:) |
Notes #
- Validation is done by the zard schemas via Darto's
validatormiddleware. On failure the request short-circuits with400 {error, target, issues}. - Params / query / headers are object schemas whose properties each become an
OpenAPI parameter. These values arrive as strings, so use
z.coerce.*for non-string types (e.g.z.coerce.int()). - Typing: Dart can't infer a schema's shape at runtime, so
c.req.valid<T>()takes an explicitT(e.g.Map<String, dynamic>). refine/transformvalidate at runtime but can't be represented in the spec.