clientforge
| Install | |
|---|---|
npm install clientforge |
|
| Latest Version: | 1.0.0 |
| License: | MIT |
| Last Updated: | Jun 22, 2026 |
| Links: | GitHub · npm |
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.
Table of Contents
- Features
- Quick Start
- Installation
- CLI Commands
- Configuration
- Target Reference
- Architecture
- Programmatic API
- Region Preservation
- OpenAPI Support
- Contributing
- License
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
TargetGeneratorinterface. - 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
As a dev dependency (recommended)
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
-
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. -
Target-based generation — Each framework (Angular, Vue, React) is a self-contained
TargetGeneratorplugin. New targets can be added by implementing a single interface. -
Naming strategy — A centralized
NamingStrategydrives all file names, class names, method names, and conflict resolution. Custom naming strategies can be plugged in. -
Region preservation — Generated files can use
/* <auto-generated NAME> */markers to protect hand-written code from being overwritten on regeneration. -
Diagnostics — Issues found during parsing, normalization, and generation are collected as structured
DiagnosticMessageobjects 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
- Create a new directory under
src/targets/<name>/. - Implement the
TargetGeneratorinterface:
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 [];
}
}
- Register the target in the pipeline's
TARGET_REGISTRYinsrc/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,OpenApiVersionOperationDefinition,ParameterDefinition,RequestBodyDefinition,ResponseDefinitionSchemaDefinition,TypeDefinition,PropertyDefinitionClientForgeConfig,TargetConfig,NamingConfigFileArtifact,GenerationContext,GenerationResultNamingStrategy,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
- Write tests. Every new feature or bug fix should include tests.
- Use the IR. Never access the raw OpenAPI document in generators — always work through the Intermediate Representation.
- No hardcoded opinions. Generated base services should not embed authentication, routing, or app-specific logic.
- Follow existing patterns. Look at the Angular/Vue/React target implementations for reference.
License
Related Packages
TypeScript GraphQL client for Propeller eCommerce V2 Platform - works with React...
One package to add GIX Copilot to an existing project: `npm add @gixcopilot/sdk`...
Version History
| Version | Released | License |
|---|---|---|
| 1.0.0 | MIT |