clientforge

Front-end SDK generator from OpenAPI specifications — supports Angular, Vue, and React
172
Install
npm install clientforge
Latest Version:1.0.0
License:MIT
Last Updated:Jun 22, 2026
Links: GitHub  ·  npm
Maintainer: icefenixdev

ClientForge

Front-end SDK generator from OpenAPI specifications — supports Angular, Vue, and React.

ClientForge reads your OpenAPI/Swagger document and generates fully-typed TypeScript models, HTTP services, and optional utilities (hooks, validators) for your front-end framework of choice.

License: MIT Node.js TypeScript


Table of Contents


Features

  • Multi-framework — generate SDKs for Angular, Vue, and React from a single config.
  • Multi-spec — Swagger 2.0, OpenAPI 3.0.x, and OpenAPI 3.1.x.
  • Type-safe — fully-typed TypeScript models, enums, unions, intersections, records, and generics.
  • Validators — optional validation functions generated alongside models for all targets.
  • Configurable output — choose model style (interface / type / class / auto), enum style (enum / union), date type, binary type, and more.
  • Smart clean — only removes auto-generated files; preserves HTTP clients, user-created models, and custom code.
  • Region preservation — regenerate only auto-generated regions; keep your custom code intact.
  • Diagnostics — structured warnings and errors during normalization and generation.
  • Extensible — plug-in architecture for targets via the TargetGenerator interface.
  • Zero runtime dependencies — generated code relies only on your framework and HTTP client.

Quick Start

# 1. Install
npm install -D clientforge

# 2. Initialize a config file
npx clientforge init

# 3. Edit clientforge.config.json — set your OpenAPI source and targets

# 4. Generate
npx clientforge generate

Installation

npm install -D clientforge
# or
pnpm add -D clientforge
# or
yarn add -D clientforge

Then use it via npx, pnpm, or an npm script:

npx clientforge generate
pnpm clientforge generate

Global install

npm install -g clientforge

After a global install, both clientforge and the short alias cf are available:

clientforge generate
cf generate
cf -g          # shortcut for generate

npm scripts

Add a script to your package.json:

{
  "scripts": {
    "generate:api": "clientforge generate"
  }
}

CLI Commands

Command Alias Description
clientforge init Create a clientforge.config.json with sensible defaults
clientforge generate cf g Generate models and services from the configured OpenAPI source
clientforge validate Validate configuration, document access, version, and target setup
clientforge inspect Print a summary of the parsed contract (schemas, operations, groups, warnings)

Configuration

Running clientforge init creates a clientforge.config.json at the project root:

{
  "input": {
    "source": "http://localhost:5000/swagger/v1/swagger.json",
    "resolveRefs": true,
  },
  "output": {
    "rootDir": "./src/api-generated",
    "clean": false,
    "format": true,
  },
  "naming": {
    "groupStrategy": "tag", // "first-segment" | "tag" | "operationId-prefix"
    "modelStyle": "auto", // "interface" | "type" | "class" | "auto"
    "enumStyle": "enum", // "enum" | "union"
    "dateType": "string", // "string" | "Date"
    "binaryType": "Blob", // "Blob" | "File" | "string"
    "typeOnlyImports": false,
  },
  "features": {
    "validators": false,
    "regionPreservation": true,
    "emitDiagnostics": true,
  },
  "targets": [
    {
      "name": "angular",
      "enabled": true,
      "outputDir": "./src/app/api",
      "httpClient": "angular-http-client",
      "generateTests": true,
    },
  ],
}

Configuration Reference

input
Field Type Default Description
source string — Required. URL or local path to an OpenAPI/Swagger document (.json, .yaml, .yml).
resolveRefs boolean true Resolve $ref pointers before normalization.
output
Field Type Default Description
rootDir string "./src/api-generated" Output root directory.
clean boolean false Remove auto-generated files before regenerating. Preserves HTTP clients and user-created files.
format boolean true Apply formatting to generated files.
naming
Field Type Default Description
groupStrategy string "tag" How operations are grouped into services: "first-segment", "tag", or "operationId-prefix".
modelStyle string "auto" Generated model form: "interface", "type", "class", or "auto" (classes for request bodies, interfaces for the rest).
enumStyle string "enum" "enum" for TypeScript enums, "union" for string literal unions.
dateType string "string" TypeScript type for date/date-time fields.
binaryType string "Blob" TypeScript type for binary fields.
typeOnlyImports boolean false Use import type syntax.
features
Field Type Default Description
validators boolean false Generate validation functions alongside models.
regionPreservation boolean true Preserve user-written code outside of auto-generated regions.
emitDiagnostics boolean true Print diagnostic messages during generation.
targets[]
Field Type Default Description
name string — "angular", "vue", or "react".
enabled boolean — Enable or disable this target.
outputDir string — Target-specific output directory.
httpClient string varies HTTP client to use (e.g. "angular-http-client", "axios", "fetch").
generateTests boolean false Generate unit test stubs (Angular).
generateHooks boolean false Generate query/mutation hooks (React).
queryLibrary string — Query library for hooks (e.g. "tanstack-query").
basePathVariable string — Variable name for the API base URL (e.g. "environment.apiUrlBase").
basePathImport string — Import path for the base URL variable.

Target Reference

Angular

Generates Angular services with HttpClient, typed Observable<T> responses, @Injectable decorators, and a reusable base HTTP service.

{
  "name": "angular",
  "enabled": true,
  "outputDir": "./src/app/api",
  "httpClient": "angular-http-client",
  "generateTests": true, // generate .spec.ts stubs
}

Generated structure:

src/app/api/
├── models/
│   ├── user.model.ts
│   ├── order.model.ts
│   └── index.ts
├── services/
│   ├── base-api.service.ts
│   ├── users.service.ts
│   ├── users.service.spec.ts
│   └── orders.service.ts

Vue

Generates pure TypeScript services for Vue with a configurable HTTP client (axios or fetch).

{
  "name": "vue",
  "enabled": true,
  "outputDir": "./src/api",
  "httpClient": "axios",
}

Generated structure:

src/api/
├── models/
│   ├── user.model.ts
│   └── index.ts
├── http/
│   └── http-client.ts
└── services/
    ├── users.service.ts
    └── orders.service.ts

React

Generates async client functions and optional TanStack Query hooks.

{
  "name": "react",
  "enabled": true,
  "outputDir": "./src/api",
  "httpClient": "fetch",
  "generateHooks": true,
  "queryLibrary": "tanstack-query",
}

Generated structure:

src/api/
├── models/
│   ├── user.model.ts
│   └── index.ts
├── http/
│   └── http-client.ts
├── clients/
│   ├── users-client.ts
│   └── orders-client.ts
└── hooks/
    ├── use-users.hook.ts
    └── use-orders.hook.ts

Architecture

ClientForge follows a pipeline architecture that cleanly separates parsing, normalization, and code generation:

┌─────────────────────────────────────────────────────────┐
│                        CLI Layer                        │
│  init · generate · validate · inspect                   │
└────────────────────────┬────────────────────────────────┘
                         │
┌────────────────────────▼────────────────────────────────┐
│                    Core Pipeline                        │
│                                                         │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  │
│  │ Config Loader │  │ Doc Loader   │  │ Version      │  │
│  │              │  │ (JSON/YAML/  │  │ Detector     │  │
│  │              │  │  URL/local)  │  │              │  │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘  │
│         │                 │                 │           │
│         │          ┌──────▼───────┐         │           │
│         │          │ Ref Resolver │◄────────┘           │
│         │          └──────┬───────┘                     │
│         │                 │                             │
│         │    ┌────────────▼────────────┐                │
│         │    │    Spec Normalizer      │                │
│         │    │  (Swagger 2 / OA 3.0 / │                │
│         │    │   OA 3.1 → unified IR) │                │
│         │    └────────────┬────────────┘                │
│         │                 │                             │
│  ┌──────▼─────────────────▼──────────────────────────┐  │
│  │          Intermediate Representation (IR)         │  │
│  │  ApiContract · SchemaDefinition · TypeDefinition  │  │
│  │  OperationDefinition · ParameterDefinition · ...  │  │
│  └───────────────────────┬───────────────────────────┘  │
│                          │                              │
│  ┌───────────────────────▼───────────────────────────┐  │
│  │           Generation Pipeline                     │  │
│  │  NamingStrategy · NameConflictResolver            │  │
│  │                                                   │  │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────────┐    │  │
│  │  │ Angular  │  │   Vue    │  │    React     │    │  │
│  │  │ Target   │  │  Target  │  │   Target     │    │  │
│  │  └────┬─────┘  └────┬─────┘  └─────┬────────┘    │  │
│  │       └──────────────┼──────────────┘             │  │
│  └──────────────────────┼────────────────────────────┘  │
│                         │                               │
│  ┌──────────────────────▼────────────────────────────┐  │
│  │           File Writer + Region Preserver          │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘

Key Design Principles

  1. Intermediate Representation (IR) — The OpenAPI document is never used directly by generators. It is first normalized into a framework-agnostic IR (ApiContract), regardless of whether the input is Swagger 2.0, OpenAPI 3.0, or 3.1.

  2. Target-based generation — Each framework (Angular, Vue, React) is a self-contained TargetGenerator plugin. New targets can be added by implementing a single interface.

  3. Naming strategy — A centralized NamingStrategy drives all file names, class names, method names, and conflict resolution. Custom naming strategies can be plugged in.

  4. Region preservation — Generated files can use /* <auto-generated NAME> */ markers to protect hand-written code from being overwritten on regeneration.

  5. Diagnostics — Issues found during parsing, normalization, and generation are collected as structured DiagnosticMessage objects rather than throwing errors.

Project Structure

src/
├── cli/                      # CLI entry point and commands
│   ├── index.ts              # Commander setup
│   └── commands/
│       ├── init.command.ts
│       ├── generate.command.ts
│       ├── validate.command.ts
│       └── inspect.command.ts
├── core/
│   ├── config/               # Config loading, defaults, validation, types
│   ├── diagnostics/          # Diagnostic collector and types
│   ├── document/             # Document loader, version detector, ref resolver
│   ├── ir/                   # Intermediate Representation types
│   ├── naming/               # Naming strategy, conflict resolution, reserved words
│   ├── normalize/            # Swagger 2 / OA 3.0 / OA 3.1 normalizers + type resolver
│   ├── pipeline/             # Generation context, pipeline orchestrator, result types
│   └── render/               # File artifact, writer, region preserver
├── plugins/
│   └── target/               # TargetGenerator interface
├── shared/                   # Shared renderers (type-renderer, service-helpers)
├── targets/
│   ├── angular/              # Angular target + renderers
│   ├── vue/                  # Vue target + renderers
│   └── react/                # React target + renderers
└── utils/                    # Path and string utilities

Adding a New Target

  1. Create a new directory under src/targets/<name>/.
  2. Implement the TargetGenerator interface:
import type { FileArtifact } from "../../core/render/file-artifact.js";
import type { GenerationContext } from "../../core/pipeline/generation-context.js";
import type { TargetGenerator } from "../../plugins/target/target.interface.js";

export class MyFrameworkTarget implements TargetGenerator {
  readonly name = "my-framework";

  generate(context: GenerationContext): FileArtifact[] {
    // Access context.contract (IR), context.config, context.naming, etc.
    // Return an array of FileArtifact objects to be written to disk.
    return [];
  }
}
  1. Register the target in the pipeline's TARGET_REGISTRY in src/core/pipeline/generation-pipeline.ts.

Programmatic API

ClientForge can be used as a library in addition to the CLI:

import {
  loadConfig,
  loadDocument,
  detectVersion,
  normalizeDocument,
  runPipeline,
  writeArtifacts,
} from "clientforge";

// 1. Load config (reads clientforge.config.json)
const config = loadConfig();

// 2. Load the OpenAPI document
const document = await loadDocument(config.input.source);

// 3. Detect spec version
const version = detectVersion(document); // "swagger2" | "openapi3.0" | "openapi3.1"

// 4. Normalize to the Intermediate Representation
const contract = normalizeDocument(document);

// 5. Run the generation pipeline (without writing to disk)
const result = runPipeline(contract, config, { write: false });

// 6. Inspect artifacts
for (const artifact of result.artifacts) {
  console.log(artifact.path, artifact.kind);
}

// 7. Optionally write to disk
writeArtifacts(result.artifacts, process.cwd());

Exported Types

All IR types are exported for custom integrations:

  • ApiContract, ApiServer, OpenApiVersion
  • OperationDefinition, ParameterDefinition, RequestBodyDefinition, ResponseDefinition
  • SchemaDefinition, TypeDefinition, PropertyDefinition
  • ClientForgeConfig, TargetConfig, NamingConfig
  • FileArtifact, GenerationContext, GenerationResult
  • NamingStrategy, DefaultNamingStrategy

Region Preservation

When features.regionPreservation is enabled, ClientForge uses auto-generated markers to protect your custom code:

/* <auto-generated imports> */
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
/* </auto-generated imports> */

// Your custom imports here — these are preserved on regeneration

/* <auto-generated methods> */
getUsers(): Observable<User[]> {
  return this.http.get<User[]>(`${this.baseUrl}/users`);
}
/* </auto-generated methods> */

// Your custom methods here — these are preserved on regeneration

On subsequent runs, only content inside the <auto-generated> markers is updated. Everything outside is preserved.


OpenAPI Support

Feature Swagger 2.0 OpenAPI 3.0 OpenAPI 3.1
JSON input ✅ ✅ ✅
YAML input ✅ ✅ ✅
URL source ✅ ✅ ✅
Local file source ✅ ✅ ✅
$ref resolution ✅ ✅ ✅
allOf ✅ ✅ ✅
oneOf — ✅ ✅
anyOf — ✅ ✅
discriminator — ✅ ✅
nullable — ✅ ✅
additionalProperties ✅ ✅ ✅
readOnly / writeOnly ✅ ✅ ✅
Security schemes ✅ ✅ ✅
Multiple servers — ✅ ✅
multipart/form-data ✅ ✅ ✅

Contributing

Contributions are welcome! Here's how to get started:

Prerequisites

  • Node.js >= 18
  • npm, pnpm, or yarn

Setup

git clone https://github.com/your-username/clientforge.git
cd clientforge
npm install

Development

# Build
npm run build

# Watch mode
npm run dev

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Run tests with coverage
npm run test:coverage

# Type-check
npm run lint

Test Structure

test/
├── fixtures/openapi/       # OpenAPI spec fixtures for tests
├── unit/                   # Unit tests for individual modules
│   ├── naming-strategy.test.ts
│   ├── type-resolver.test.ts
│   ├── normalizers.test.ts
│   ├── region-preserver.test.ts
│   └── ...
└── integration/
    └── pipeline.test.ts    # End-to-end pipeline integration tests

Guidelines

  1. Write tests. Every new feature or bug fix should include tests.
  2. Use the IR. Never access the raw OpenAPI document in generators — always work through the Intermediate Representation.
  3. No hardcoded opinions. Generated base services should not embed authentication, routing, or app-specific logic.
  4. Follow existing patterns. Look at the Angular/Vue/React target implementations for reference.

License

MIT

Related Packages

@hey-api/nuxt

🚀 Nuxt module for `@hey-api/openapi-ts` codegen.

71,945 5,513
@propeller-commerce/propeller-sdk-v2

TypeScript GraphQL client for Propeller eCommerce V2 Platform - works with React...

8,078 1
@gixcopilot/sdk

One package to add GIX Copilot to an existing project: `npm add @gixcopilot/sdk`...

105 0
iflow-engine-base

BIM Engine SDK for Vue2, Vue3, React and HTML

29,473
iflow-engine-base-3d

BIM Engine SDK for Vue2, Vue3, React and HTML

9,510

Version History

Version Released License
1.0.0 MIT