OpenAPI Generator
The @ng-forge/openapi-generator reads your OpenAPI 3.x spec and produces ready-to-use FormConfig objects and TypeScript interfaces. No manual field wiring: your API contract drives your forms.
Key features:
- Generates
as const satisfies FormConfigfor full type inference - Maps OpenAPI types, formats, and constraints to field types and validators
- Interactive mode for resolving ambiguous field types (e.g. input vs textarea)
- Watch mode for regeneration on spec changes
- Persists decisions in a config file for reproducible builds
Installation
Run directly with npx:
npx @ng-forge/openapi-generator --spec ./openapi.yaml --output ./src/formsOr install as a dev dependency:
npm install -D @ng-forge/openapi-generatorQuick Start
Given a Petstore-like OpenAPI spec:
openapi: 3.0.3
info:
title: Petstore
version: 1.0.0
paths:
/pets:
post:
operationId: createPet
requestBody:
content:
application/json:
schema:
type: object
required: [name]
properties:
name:
type: string
minLength: 1
maxLength: 100
age:
type: integer
minimum: 0
email:
type: string
format: email
status:
type: string
enum: [available, pending, sold]Run the generator:
npx @ng-forge/openapi-generator --spec ./petstore.yaml --output ./src/formsThis produces:
src/forms/forms/create-pet.form.ts
// @generated by @ng-forge/openapi-generator
import type { FormConfig } from '@ng-forge/dynamic-forms';
export const createPetFormConfig = {
fields: [
{
key: 'name',
type: 'input',
label: 'Name',
props: { type: 'text' },
validators: [{ type: 'required' }, { type: 'minLength', value: 1 }, { type: 'maxLength', value: 100 }],
},
{
key: 'age',
type: 'input',
label: 'Age',
props: { type: 'number' },
validators: [{ type: 'min', value: 0 }],
},
{
key: 'email',
type: 'input',
label: 'Email',
props: { type: 'email' },
validators: [{ type: 'email' }],
},
{
key: 'status',
type: 'select',
label: 'Status',
options: [
{ label: 'Available', value: 'available' },
{ label: 'Pending', value: 'pending' },
{ label: 'Sold', value: 'sold' },
],
},
],
} as const satisfies FormConfig;src/forms/types/create-pet.types.ts
// @generated by @ng-forge/openapi-generator
export interface CreatePetFormValue {
name: string;
age?: number;
email?: string;
status?: 'available' | 'pending' | 'sold';
}Both directories include barrel index.ts files for convenient imports.
CLI Reference
ng-forge-generator [options]| Flag | Type | Default | Description |
|---|---|---|---|
--spec |
string |
(required) | Path to OpenAPI 3.x spec file (JSON or YAML) |
--output |
string |
(required) | Output directory for generated files |
--interactive |
'full' | 'none' |
'full' |
'full' prompts for ambiguous fields; 'none' uses defaults |
--endpoints |
string |
(none) | Comma-separated endpoints: POST:/pets,GET:/pets/{id} |
--read-only |
boolean |
false |
Generate GET endpoint forms with all fields disabled |
--watch |
boolean |
false |
Watch spec file and regenerate on changes |
--config |
string |
|
Directory containing .ng-forge-generator.json |
--dry-run |
boolean |
false |
List files that would be generated without writing them |
--skip-existing |
boolean |
false |
Skip files that already exist on disk |
--barrel-extension |
string |
"" |
Extension used in barrel file exports, e.g. .js for Node ESM; empty for bundler/Angular setups |
--verbose |
boolean |
false |
Show detailed output including field mapping decisions |
--quiet |
boolean |
false |
Suppress info output; still shows success summary, warnings, and errors |
OpenAPI to Field Type Mapping
The generator maps OpenAPI schema types and formats to @ng-forge/dynamic-forms field types:
| OpenAPI Type | Format | Field Type | Props |
|---|---|---|---|
string |
email |
input |
{ type: 'email' } |
string |
uri / url |
input |
{ type: 'url' } |
string |
date / date-time |
datepicker |
(none) |
string |
password |
input |
{ type: 'password' } |
string |
(none) | input |
{ type: 'text' } |
string |
+ enum |
select |
(none) |
integer / number |
(any) | input |
{ type: 'number' } |
boolean |
(any) | checkbox |
(none) |
array |
+ enum items | multi-checkbox |
(none) |
array |
+ object items | array |
(container) |
object |
(any) | group |
(container) |
Nullable Values
OpenAPI nullability is preserved end-to-end:
| OpenAPI Spec | Schema Example | Emitted FieldDef |
|---|---|---|
| 3.0 | { type: 'string', nullable: true } |
nullable: true |
| 3.1 | { type: ['string', 'null'] } |
nullable: true |
| Either | { nullable: true, default: null } |
nullable: true, value: null |
See Nullable values in Configuration for runtime behavior and the read-side caveat.
Ambiguous Field Types
Some mappings have alternatives. In interactive mode, the CLI prompts you to choose:
| Scope | Default | Alternative |
|---|---|---|
| Text input | input (single-line) |
textarea (multi-line) |
| Single select | select (dropdown) |
radio (radio buttons) |
| Numeric | input (number) |
slider (range) |
| Boolean | checkbox |
toggle (switch) |
In non-interactive mode (--interactive none), the Default column is used automatically.
Validator Mapping
OpenAPI schema constraints map directly to @ng-forge/dynamic-forms validators:
| OpenAPI Property | Validator | Value |
|---|---|---|
Field in required array |
required |
(none) |
minLength |
minLength |
number |
maxLength |
maxLength |
number |
minimum |
min |
number |
maximum |
max |
number |
pattern |
pattern |
regex string |
format: 'email' |
email |
(none) |
Schema Support
| Schema Structure | Support | Notes |
|---|---|---|
Plain properties |
Supported | Maps each property to a field |
allOf |
Supported | Merges schemas, combines required arrays |
oneOf + discriminator |
Supported | Creates conditional groups with radio discriminator |
anyOf |
Skipped | Warning logged |
if/then/else |
Skipped | Warning logged |
additionalProperties |
Skipped | Warning logged |
$ref |
Dereferenced | Resolved at parse time via swagger-parser |
Request Body Content Types
Request body schemas are read from application/json, multipart/form-data, or application/x-www-form-urlencoded, in that preference order when an endpoint declares more than one.
Binary file properties (type: string with format: binary, including arrays of them) are skipped with a warning since no file upload field type exists yet. An endpoint whose body contains only binary properties produces no form and is skipped entirely.
Config File
The generator persists your choices in .ng-forge-generator.json:
{
"spec": "./openapi.yaml",
"output": "./src/forms",
"endpoints": ["POST:/pets", "GET:/pets/{id}"],
"decisions": {
"description": "textarea",
"age": "slider"
},
"readOnly": true
}On subsequent runs, persisted decisions are reused, so interactive prompts only appear for new or changed fields.
Interactive vs Non-Interactive Mode
Interactive (--interactive full) is the default:
- Prompts you to select which endpoints to generate forms for (all endpoints are pre-selected; uncheck the ones you don't want)
- Prompts for each ambiguous field type choice
- Saves decisions to the config file
Non-interactive (--interactive none):
- Uses all endpoints, or filters by
--endpointsflag - Uses default field type choices for ambiguous fields
- No prompts, suitable for CI/CD pipelines
Watch Mode
npx @ng-forge/openapi-generator \
--spec ./openapi.yaml \
--output ./src/forms \
--watchWatch mode monitors your spec file and regenerates forms on changes:
- Uses a 500ms debounce to avoid thrashing
- Runs in non-interactive mode (uses persisted decisions)
- Press
Ctrl+Cto stop
Output Structure
Generated files follow this layout:
<output-dir>/
├── forms/
│ ├── create-pet.form.ts
│ ├── list-pets.form.ts
│ └── index.ts
└── types/
├── create-pet.types.ts
├── list-pets.types.ts
└── index.tsFile names are derived from operationId if available, otherwise from the HTTP method and path (e.g. POST /pets/{id}/tags becomes post-pets-by-id-tags).
GET Endpoints
By default, GET endpoints are included with editable fields, just like POST/PUT/PATCH. Use the --read-only flag to generate GET endpoint fields with disabled: true:
npx @ng-forge/openapi-generator \
--spec ./openapi.yaml \
--output ./src/forms \
--read-onlyTop-level array responses are always skipped with a warning.
Programmatic API
The package exports its internals for programmatic use:
import {
// Parsing
parseOpenAPISpec,
extractEndpoints,
// Mapping
mapSchemaToFieldType,
mapSchemaToValidators,
mapSchemaToFields,
// Generation
generateFormConfig,
generateInterface,
generateBarrel,
writeGeneratedFiles,
// Configuration
loadConfig,
saveConfig,
// CLI
run,
} from '@ng-forge/openapi-generator';Use these to integrate form generation into custom build pipelines, Nx generators, or CI workflows.