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 FormConfig for 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/forms

Or install as a dev dependency:

npm install -D @ng-forge/openapi-generator

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/forms

This 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:

  1. Prompts you to select which endpoints to generate forms for (all endpoints are pre-selected; uncheck the ones you don't want)
  2. Prompts for each ambiguous field type choice
  3. Saves decisions to the config file

Non-interactive (--interactive none):

  • Uses all endpoints, or filters by --endpoints flag
  • 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 \
  --watch

Watch 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+C to 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.ts

File 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-only

Top-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.