Package Exports
- @http-forge/codegen
Readme
@http-forge/codegen
Generate typed TypeScript API clients from HTTP Forge collections.
Features
- 🔧 CLI tool for generating TypeScript clients from HTTP Forge collections
- 📝 Type-safe interfaces for headers, query params, path params, and request bodies
- 📐 Schema-first generation — uses
body.schema.jsonandresponse.schema.jsonwhen available - 🏷️ Typed response wrappers — generates
TypedAPIResponsewithjson(): Promise<ResponseType>from response schemas - 🔤 Typed parameters — rich metadata (type, required, enum, format, description, deprecated) for headers, query, and path params
- 🔗 Path param constraint detection — enum constraints become union types, regex patterns become
stringwith@patternJSDoc - 🔄
{{variable}}resolution in generated request payloads - 📦 Barrel export generation with recursive
index.tsfiles - 🎯 Generate all collections, a single collection, or a single request
- ⚙️ Optional type-only generation for schema-first workflows
- 📋 Supports JSON, form-urlencoded, form-data (with file uploads), GraphQL, binary, and raw text body types
Installation
npm install @http-forge/codegenQuick Start
CLI usage
# Generate all collections
npx http-forge-codegen --input ./collections --output ./api-clients
# Generate a single collection
npx http-forge-codegen -i ./collections -o ./api-clients -c forgerock-login
# Generate a single request
npx http-forge-codegen -i ./collections -o ./api-clients -r forgerock-login/login-request
# Overwrite existing generated files
npx http-forge-codegen -i ./collections -o ./api-clients --overwrite
# Generate only type definitions
npx http-forge-codegen -i ./collections -o ./api-clients --types-only
# Skip barrel file updates for single request/collection generation
npx http-forge-codegen -i ./collections -o ./api-clients -r forgerock-login/login-request --no-barrelCLI options
| Flag | Description |
|---|---|
-i, --input <path> |
Input directory containing collection source files (required) |
-o, --output <path> |
Output directory for generated files (required) |
-r, --request <path> |
Generate a single request by path (e.g., collection/request) |
-c, --collection <name> |
Generate a single collection |
--overwrite |
Overwrite existing files (default: false) |
--types-only |
Generate only TypeScript types without runtime request functions |
--no-barrel |
Skip index.ts barrel file generation |
Programmatic usage
import { generateClients, generateCollection, generateSingleRequest } from '@http-forge/codegen';
// Generate all collections
await generateClients({
input: './collections',
output: './api-clients',
overwrite: true,
});
// Generate a single collection
await generateCollection({
input: './collections',
output: './api-clients',
collection: 'forgerock-login',
});
// Generate a single request
await generateSingleRequest({
input: './collections',
output: './api-clients',
request: 'forgerock-login/login-request',
updateBarrel: false,
});Programmatic option types
| Function | Options Type |
|---|---|
generateClients(options) |
GeneratorOptions |
generateCollection(options) |
CollectionOptions |
generateSingleRequest(options) |
SingleRequestOptions |
Common option fields:
| Field | Type | Description |
|---|---|---|
input |
string |
Collection source directory |
output |
string |
Generated output directory |
overwrite? |
boolean |
Whether to overwrite existing files |
typesOnly? |
boolean |
Emit only type definitions |
updateBarrel? |
boolean |
Update barrel exports after generating a single collection or request |
Collection structure
The codegen reads HTTP Forge collection folders. Each request is a directory containing:
collections/
└── my-api/
└── get-user/
├── request.json # Method, URL, headers, query params, path params
├── body.json # Request body (optional, overrides inline body)
├── body.schema.json # JSON Schema for request body (optional)
└── response.schema.json # Response schemas per status code (optional)Schema files
body.schema.json — When present, the codegen generates the request body interface from this JSON Schema instead of inferring types from body.json sample data. Supports $ref, oneOf/anyOf/allOf, nested objects, and components for shared definitions.
response.schema.json — Defines response types per HTTP status code. Generates per-status interfaces (e.g., Response200, Response404) and a typed response wrapper with json(): Promise<PrimaryResponseType>.
{
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": { "type": "string" },
"name": { "type": "string" }
},
"required": ["id"]
}
}
}
}
}
}Generated output
File structure
api-clients/
├── forgerock-login/
│ ├── login-request.ts
│ ├── form-submission.ts
│ ├── user-sessions.ts
│ └── index.ts
├── user-api/
│ └── ...
└── index.tsGenerated code example
Each request file contains typed interfaces and an async function:
import type { HttpHeaders, BaseRequestContext, BaseApiOptions } from '@http-forge/playwright';
import type { APIResponse } from '@playwright/test';
// Headers interface (typed metadata when available)
export interface GetUserHeaders extends HttpHeaders {
/** Authorization token — @default "Bearer {{accessToken}}" */
'Authorization'?: string;
}
// Path params interface with constraint-based types
export interface GetUserPathParams {
/** Path parameter: contentType */
contentType: 'VOD' | 'PROGRAM'; // enum constraint → union type
/** Path parameter: appversion — @pattern T7.[0-9] */
appversion: string; // regex constraint → string
userId: any; // no constraint → any
}
// Query params interface (typed metadata when available)
export interface GetUserQuery {
/** Filter by status — @format enum */
status?: 'active' | 'inactive';
/** Page number */
page?: number;
[key: string]: any;
}
// Body interface (from body.schema.json when available)
export interface GetUserBody {
name: string;
email?: string;
}
// Response interface (from response.schema.json)
/** Success */
export interface GetUserResponse200 {
id: string;
name?: string;
}
// Typed response wrapper
export interface GetUserTypedResponse extends APIResponse {
json(): Promise<GetUserResponse200>;
}
// Options interface
export interface GetUserOptions extends BaseRequestContext<GetUserHeaders>, BaseApiOptions {
params: GetUserPathParams;
query?: GetUserQuery;
body?: GetUserBody;
}
// Async request function
export async function getUser(options: GetUserOptions): Promise<GetUserTypedResponse> {
// ... URL resolution, header merging, Playwright request
}Type generation priority
| Source | Priority | Description |
|---|---|---|
body.schema.json |
Highest | JSON Schema → full interface with required/optional, JSDoc, nested types |
body.json |
Fallback | Sample data → inferred interface with any types and @default comments |
Inline body in request.json |
Lowest | Same as body.json |
Path parameter constraints
Path params extracted from URL patterns like :name(constraint)? are turned into TypeScript types:
| URL pattern | Constraint | Generated type |
|---|---|---|
:contentType(VOD|PROGRAM) |
VOD|PROGRAM |
'VOD' | 'PROGRAM' |
:provider(TELUS) |
TELUS |
'TELUS' |
:appversion(T7.[0-9]) |
T7.[0-9] |
string (with @pattern JSDoc) |
:userId |
none | any |
:sessionId? |
none | any (optional) |
Body type support
| Body type | Generated interface | Runtime handling |
|---|---|---|
json / raw (json format) |
Object interface or schema | data: with env.resolveObject() |
x-www-form-urlencoded |
Interface from field array | form: |
form-data |
Interface from field array | multipart: (files) or form: (text) |
graphql |
{ query, variables, operationName } |
Merges defaults, resolves query |
binary |
Buffer | string |
Base64 → Buffer conversion |
raw (text/xml/html/js) |
string type alias |
data: with env.resolve() |
Exported types
The package exports the following types for programmatic use:
import type {
GeneratorOptions,
SingleRequestOptions,
CollectionOptions,
CollectionInfo,
RequestInfo,
TypedParam,
} from '@http-forge/codegen';Development
npm install
npm run build
npm testLicense
MIT