NAME
Mojolicious::Plugin::Fondation::OpenAPI::Command::openapi - Generate OpenAPI specification from DBIx::Class sources
VERSION
version 0.02
SYNOPSIS
$ myapp.pl openapi generate
$ myapp.pl openapi generate -y
$ myapp.pl openapi generate --output custom.json
DESCRIPTION
Command-line interface for generating an OpenAPI 3.0.3 specification from DBIx::Class sources discovered via Fondation::Model::DBIx::Async.
No database connection is required -- sources are read from the schema class metadata via $schema_class->sources.
NAME
Mojolicious::Plugin::Fondation::OpenAPI::Command::openapi - Generate OpenAPI specification from DBIx::Class sources
This module is more than experimental !
DESIGN
Two layers
The generator works with two conceptual layers:
- DBIx source
-
The raw database structure: column types, constraints, defaults.
- API Base
-
The canonical OpenAPI representation of the resource. Built from the DBIx source with implicit rules applied, then overridden by
extra->{openapi}annotations and plugin configuration.
Implicit rules
The following rules are derived automatically from DBIx structure and require no extra->{openapi} annotations:
DBIx -> OpenAPI
───────────────────────────── ───────
is_auto_increment = 1 readOnly: true
column named created_at readOnly: true
column named updated_at readOnly: true
data_type =~ /^date$/i format: "date"
data_type =~ /datetime/i format: "date-time"
data_type =~ /timestamp/i format: "date-time"
data_type =~ /^float$/i format: "float"
data_type =~ /^double$/i format: "double"
is_nullable = 0 required (unless writeOnly/readOnly)
size = N (string type) maxLength: N
data_type =~ /int|serial/i type: "integer"
data_type =~ /float|decimal/i type: "number"
data_type =~ /boolean/i type: "boolean"
default_value default
is_nullable = 1 nullable: true
extra->{openapi} annotations
Semantic choices that cannot be derived from DBIx are declared in the Result class via extra->{openapi}:
username => {
data_type => 'varchar', size => 100, is_nullable => 0,
extra => {
openapi => {
minLength => 4,
},
},
},
Flat keys (apply to all contexts)
format -- "email", "password", "uri", etc.
minLength -- minimum string length
maxLength -- maximum string length (overrides DBIx size)
minimum -- minimum numeric value
maximum -- maximum numeric value
enum -- arrayref of allowed values
writeOnly -- boolean, field only sent in requests
readOnly -- boolean, field only sent in responses (overrides implicit)
description -- human-readable description
type -- override the inferred OpenAPI type
nullable -- override the inferred nullability
default -- override the inferred default value
Contextual keys (per-operation overrides)
create => { required => 1 } # force required on POST
create => { required => 0 } # force optional on POST
update => { required => 1 } # force required on PUT
update => { required => 0 } # force optional on PUT
read => { required => 1 } # force required on GET item
read => { required => 0 } # force optional on GET item
list => { required => 1 } # force required on GET collection
list => { required => 0 } # force optional on GET collection
Conditional schema generation
Contextual schemas (UserCreate, UserUpdate, UserRead, UserList) are generated only when they differ from the API Base. Comparison considers both property names and the required array.
A simple source like Group with no contextual rules produces a single canonical schema used everywhere. A complex source like User with password having create.required => 1 and update.required => 0 produces User, UserCreate, and UserUpdate.
writeOnly handling
Fields marked writeOnly are:
Excluded from the API Base
requiredarrayExcluded from the API Base
propertieshashAdded back into
createandupdateprojection properties
This means GET responses never contain writeOnly fields and the OpenAPI validator does not expect them.
Config override
Any column property can be overridden via the plugin configuration without modifying DBIx classes:
'Fondation::OpenAPI' => {
backend => 'main',
schemas => {
User => {
columns => {
name => {
maxLength => 100, # override DBIx size
},
password => {
writeOnly => 1,
create => { required => 1 },
update => { required => 0 },
},
},
},
},
},
Config keys follow the same flat + contextual structure as extra->{openapi} and take the highest priority in the cascade:
1. Structure DBIx (implicit)
2. extra->{openapi} flat keys (Result class)
3. Config flat keys (myapp.conf)
4. extra->{openapi} contextual (Result class)
5. Config contextual (myapp.conf)
SUBCOMMANDS
generate
myapp.pl openapi generate
myapp.pl openapi generate -y
myapp.pl openapi generate --output custom.json
Iterates all DBIx sources (monikers), builds the API Base for each, applies contextual projections, and writes two files:
-
OpenAPI 3.0.3 specification with schemas and CRUD paths. Loaded at runtime by Mojolicious::Plugin::OpenAPI for request validation.
public/js/validators.js-
Client-side validation (
FondationValidators.validate()) consumed by Fondation::Asset bundles.
Options:
--output FILE Output path relative to $app->home (default: share/openapi.json)
-y Overwrite without confirmation prompt
CRUD PATHS
Each source generates five endpoints with x-mojo-to routing and automatic x-auth permission annotations:
GET /{moniker} -> {Moniker}#list x-auth: {moniker_lc}_list
POST /{moniker} -> {Moniker}#create x-auth: {moniker_lc}_create
GET /{moniker}/{id} -> {Moniker}#read x-auth: {moniker_lc}_read
PUT /{moniker}/{id} -> {Moniker}#update x-auth: {moniker_lc}_update
DELETE /{moniker}/{id} -> {Moniker}#delete x-auth: {moniker_lc}_delete
The x-auth default can be overridden via the plugin config (schemas.{Source}.x_auth.{operation}). See Mojolicious::Plugin::Fondation::OpenAPI for details. Enforcement is handled at runtime by Mojolicious::Plugin::Fondation::OpenAPI::Security.
SEE ALSO
Mojolicious::Plugin::Fondation::OpenAPI, Fondation::Model::DBIx::Async, Mojolicious::Plugin::OpenAPI
AUTHOR
Daniel Brosseau <dab@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2026 by Daniel Brosseau.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.