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:
Quick 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 |
— | 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 |
--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 |
— |
string |
password |
input |
{ type: 'password' } |
string |
(none) | input |
{ type: 'text' } |
string |
+ enum |
select |
— |
integer / number |
(any) | input |
{ type: 'number' } |
boolean |
(any) | checkbox |
— |
array |
+ enum items | multi-checkbox |
— |
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 Configuration → Nullable values 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 |
— |
minLength |
minLength |
number |
maxLength |
maxLength |
number |
minimum |
min |
number |
maximum |
max |
number |
pattern |
pattern |
regex string |
format: 'email' |
email |
— |
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 |
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) — the default:
- Prompts you to select which endpoints to generate forms for (POST/PUT/PATCH are pre-selected, GET is unchecked)
- 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 → 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.