@azwebmaster/openapi-to-ts
v0.0.18
Published
> π **Generate fully-typed TypeScript clients from OpenAPI specs in seconds**
Downloads
165
Readme
OpenAPI to TypeScript
π Generate fully-typed TypeScript clients from OpenAPI specs in seconds
Transform your OpenAPI 3.0+ specifications into production-ready TypeScript clients with full type safety, IntelliSense support, and zero configuration.
β¨ Why This Generator?
- π― Zero Config: Works out of the box with any OpenAPI 3.0+ spec
- π Type Safe: Full TypeScript support with discriminated unions, nullable types, and schema composition
- β‘ Fast: Built with ts-morph for lightning-fast code generation
- π οΈ Developer Friendly: Rich JSDoc comments, IntelliSense, and error-free generated code
- π¦ Modern: Uses Axios with modern TypeScript patterns and ES modules
π Quick Start
Install
# For CLI usage (recommended)
npm install -g @azwebmaster/openapi-to-ts
# Or using bun
bun install -g @azwebmaster/openapi-to-ts
# For programmatic usage in your project
npm install @azwebmaster/openapi-to-ts
# or
bun add @azwebmaster/openapi-to-tsCLI Usage (Recommended)
The CLI is the easiest way to generate TypeScript clients:
# Basic generation
openapi-to-ts generate ./api.yaml
# Generate from URL
openapi-to-ts generate https://api.example.com/openapi.json
# With custom options
openapi-to-ts generate ./api.yaml \
--output ./src/api \
--namespace MyAPI \
--type-output file-per-type
# Preview what will be generated (dry run)
openapi-to-ts generate ./api.yaml --dry-run
# Show API information
openapi-to-ts info ./api.yamlProgrammatic Usage
For integration into build scripts or custom tooling:
import { generateFromSpec } from '@azwebmaster/openapi-to-ts';
await generateFromSpec({
inputSpec: './api.yaml',
outputDir: './generated/api',
namespace: 'MyAPI',
typeOutputMode: 'single-file'
});Use Your Generated Client
import { createClient } from './generated/api';
const api = createClient('https://api.example.com', {
headers: { Authorization: 'Bearer YOUR_TOKEN' }
});
// Fully typed with IntelliSense! π
const users = await api.getUsers({ page: 1, limit: 10 });
const newUser = await api.createUser({
email: '[email protected]',
name: 'John Doe'
});π What You Get
Generated Files
generated/
βββ types.ts # All TypeScript interfaces
βββ client.ts # Axios-based API client
βββ index.ts # Exports and factory functionExample Generated Types
// types.ts
export interface User {
id: string;
email: string;
name: string;
avatar?: string | null;
preferences?: UserPreferences;
}
export interface CreateUserRequest {
email: string;
name: string;
password: string;
age?: number;
}Example Generated Client
// client.ts
export class MyAPIClient {
constructor(baseURL: string, config?: AxiosRequestConfig) {
this.client = axios.create({ baseURL, ...config });
}
async getUsers(params?: GetUsersParams): Promise<AxiosResponse<User[]>> {
return this.client.get('/users', { params });
}
async createUser(data: CreateUserRequest): Promise<AxiosResponse<User>> {
return this.client.post('/users', data);
}
}π― Advanced Features
Configuration File System
For complex projects, use .ott.json configuration files to manage multiple APIs and operation filtering:
# Initialize configuration from OpenAPI spec
openapi-to-ts init ./api.yaml
# List available operations
openapi-to-ts list
# Generate only selected operations
openapi-to-ts generate --config --operation-ids "getUsers,createUser"Configuration files support:
- Multiple APIs: Generate clients for different OpenAPI specs
- Operation Filtering: Select only the operations you need
- Persistent Settings: Save generation options for team collaboration
- CI/CD Integration: Use config files in automated builds
Schema Composition Support
# OpenAPI spec
components:
schemas:
Pet:
oneOf:
- $ref: '#/components/schemas/Dog'
- $ref: '#/components/schemas/Cat'
discriminator:
propertyName: petType
Dog:
allOf:
- $ref: '#/components/schemas/BasePet'
- type: object
properties:
breed: { type: string }// Generated TypeScript
export type Pet = Dog | Cat;
export interface Dog extends BasePet {
petType: "dog";
breed: string;
}
// TypeScript narrows the type automatically! π
pets.forEach(pet => {
if (pet.petType === "dog") {
console.log(pet.breed); // TypeScript knows this is a Dog
}
});Nullable Types & Union Types
// OpenAPI 3.0 nullable
avatar?: string | null;
// OpenAPI 3.1 type arrays
status: "active" | "inactive" | "pending";
// Complex unions with anyOf
vehicle: Car | Truck | Motorcycle;Namespace Organization
// Organized by operationId namespaces
const api = createClient('https://api.example.com');
// Direct methods
await api.getUsers();
await api.createUser(data);
// Namespaced methods
await api.users.getProfile();
await api.users.updateSettings(data);
await api.admin.getSystemStats();βοΈ Configuration File System
For complex projects or when you need to generate multiple API clients, use the configuration file system with .ott.json:
Initialize Configuration
# Create configuration from OpenAPI spec
openapi-to-ts init ./api.yaml
# With custom output directory
openapi-to-ts init ./api.yaml -o ./src/api
# From remote URL
openapi-to-ts init https://api.example.com/openapi.jsonConfiguration File Format
The generated .ott.json file contains:
{
"apis": [
{
"name": "My API",
"spec": "./api.yaml",
"output": "./generated",
"namespace": "MyAPI",
"axiosInstance": "apiClient",
"typeOutput": "single-file",
"headers": {
"Authorization": "Bearer ${API_TOKEN}"
},
"operationIds": [
"getUsers",
"createUser",
"updateUser"
]
}
]
}Configuration Commands
# List available operations from config
openapi-to-ts list
# List operations for specific API (if multiple APIs)
openapi-to-ts list --api "My API"
# Generate using configuration file
openapi-to-ts generate --config
# Generate specific operations from CLI
openapi-to-ts generate --config --operation-ids "getUsers,createUser"Benefits of Configuration Files
- Operation Filtering: Generate only the operations you need
- Multiple APIs: Manage multiple OpenAPI specs in one project
- Persistent Settings: Save generation options for repeated use
- Team Collaboration: Share configuration with your team
- CI/CD Integration: Use config files in automated builds
π οΈ CLI Reference
Commands
# Generate TypeScript client
openapi-to-ts generate <spec> [options]
# Initialize configuration file
openapi-to-ts init <spec> [options]
# List operations from config
openapi-to-ts list [options]
# Show API specification info
openapi-to-ts info <spec>
# Show usage examples and tips
openapi-to-ts examplesGenerate Command Options
| Option | Description | Default |
|--------|-------------|---------|
| -o, --output <dir> | Output directory for generated files | ./generated |
| -n, --namespace <name> | Namespace for the generated client class | API |
| -a, --axios-instance <name> | Name for the Axios instance variable | apiClient |
| -t, --type-output <mode> | Type organization: single-file, file-per-type, group-by-tag | single-file |
| -H, --header <header> | Add header for URL requests (format: "Name: Value") | - |
| --dry-run | Preview generation without writing files | false |
CLI Examples
# Basic generation from local file
openapi-to-ts generate api.yaml
# Generate from remote URL
openapi-to-ts generate https://api.example.com/openapi.json
# Generate with authentication headers
openapi-to-ts generate https://api.example.com/openapi.json \
-H "Authorization: Bearer your-token" \
-H "X-API-Key: your-api-key"
# Generate with environment variable headers
openapi-to-ts generate https://api.example.com/openapi.json \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "X-API-Key: ${API_KEY:default-key}"
# Custom output directory and namespace
openapi-to-ts generate api.yaml -o ./src/api -n GitHubAPI
# Different type organization modes
openapi-to-ts generate api.yaml -t file-per-type # One file per type
openapi-to-ts generate api.yaml -t group-by-tag # Group by OpenAPI tags
# Preview what will be generated
openapi-to-ts generate api.yaml --dry-run
# Configuration file workflow
openapi-to-ts init api.yaml # Create .ott.json config
openapi-to-ts list # List available operations
openapi-to-ts generate --config # Generate using config
openapi-to-ts generate --config --operation-ids "getUsers,createUser" # Generate specific operations
# Show API specification information
openapi-to-ts info api.yaml
openapi-to-ts info https://api.example.com/openapi.json
# Get help and examples
openapi-to-ts examples
openapi-to-ts --helpEnvironment Variables in Headers
You can use environment variables in header values to keep sensitive information out of your configuration files and command history. This is especially useful for API keys, tokens, and other credentials.
Syntax
${VAR_NAME}- Use the value of the environment variableVAR_NAME${VAR_NAME:default_value}- Use the environment variableVAR_NAME, ordefault_valueif not set${VAR_NAME:}- Use the environment variableVAR_NAME, or empty string if not set
Examples
# Set environment variables
export API_TOKEN="your-secret-token"
export API_KEY="your-api-key"
# Use in CLI commands
openapi-to-ts generate https://api.example.com/openapi.json \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "X-API-Key: ${API_KEY}"
# With default values
openapi-to-ts generate https://api.example.com/openapi.json \
-H "Authorization: Bearer ${API_TOKEN:guest}" \
-H "X-API-Key: ${API_KEY:demo-key}"Configuration Files
Environment variables also work in .ott.json configuration files:
{
"apis": [
{
"name": "MyAPI",
"spec": "https://api.example.com/openapi.json",
"headers": {
"Authorization": "Bearer ${API_TOKEN}",
"X-API-Key": "${API_KEY:default-key}",
"X-Environment": "${ENV:development}"
}
}
]
}Security Best Practices
- Never commit environment variables to version control
- Use
.envfiles for local development (not supported by this tool, use your shell or process manager) - Use default values for non-sensitive configuration
- Keep sensitive tokens in secure environment variable management systems
Type Output Modes
single-file(default): All types in onetypes.tsfilefile-per-type: Each type in its own file undertypes/directorygroup-by-tag: Types grouped by OpenAPI tags/categories
π§ Programmatic Usage
For integration into build scripts, CI/CD pipelines, or custom tooling:
import { generateFromSpec, TypeOutputMode } from '@azwebmaster/openapi-to-ts';
// Basic usage
await generateFromSpec({
spec: './api.yaml',
outputDir: './generated/api',
namespace: 'MyAPI'
});
// Advanced usage with all options
await generateFromSpec({
spec: 'https://api.example.com/openapi.json',
outputDir: './src/generated',
namespace: 'GitHubAPI',
axiosInstanceName: 'githubClient',
typeOutputMode: TypeOutputMode.FilePerType,
headers: {
'Authorization': 'Bearer ${API_TOKEN}',
'X-API-Key': '${API_KEY:default-key}'
},
operationIds: ['getUsers', 'createUser', 'updateUser']
});Generator Options
interface GeneratorOptions {
spec: string; // Path to OpenAPI spec file or URL
outputDir: string; // Output directory for generated files
namespace?: string; // Client namespace (default: 'API')
axiosInstanceName?: string; // Name for Axios instance (default: 'apiClient')
headers?: Record<string, string>; // HTTP headers for remote specs
typeOutputMode?: TypeOutputMode; // How to organize generated types
operationIds?: string[]; // Filter specific operations to generate
}
enum TypeOutputMode {
SingleFile = 'single-file', // All types in one file
FilePerType = 'file-per-type', // One file per type
GroupByTag = 'group-by-tag' // Group by OpenAPI tags
}Build Script Integration
// scripts/generate-api.ts
import { generateFromSpec, TypeOutputMode } from '@azwebmaster/openapi-to-ts';
async function generateAPI() {
try {
await generateFromSpec({
spec: './api/openapi.yaml',
outputDir: './src/api/generated',
namespace: 'MyAPI',
typeOutputMode: TypeOutputMode.SingleFile,
operationIds: ['getUsers', 'createUser', 'updateUser'] // Only generate specific operations
});
console.log('β
API client generated successfully');
} catch (error) {
console.error('β Failed to generate API client:', error);
process.exit(1);
}
}
generateAPI();// package.json
{
"scripts": {
"generate:api": "tsx scripts/generate-api.ts",
"build": "npm run generate:api && tsc"
}
}π¨ Supported OpenAPI Features
β Schema Features
- Composition:
anyOf,oneOf,allOf - Discriminated Unions: With proper TypeScript narrowing
- Nullable Types: OpenAPI 3.0
nullableand 3.1typearrays - Const Values: Literal types
- Enums: String and numeric unions
- Inheritance: Schema extension with
allOf
β Type System
- Primitives:
string,number,boolean,integer - Arrays:
Array<T>with typed items - Objects: Interfaces with required/optional properties
- References:
$refresolution across components - Additional Properties:
Record<string, T>
β API Features
- All HTTP Methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
- Parameters: Path, query, header parameters
- Request Bodies: Typed request data
- Responses: Full response typing
- Authentication: Header-based auth support
π― Real-World Example
Let's generate a client for a user management API:
# Generate the client
openapi-to-ts generate user-api.yaml -o ./src/api -n UserAPI// Use the generated client
import { createClient } from './src/api';
const userAPI = createClient('https://api.myapp.com', {
headers: { Authorization: `Bearer ${token}` }
});
// Get users with pagination
const { data } = await userAPI.getUsers({
page: 1,
limit: 20,
sort: 'created_at',
order: 'desc'
});
// Create a new user
const newUser = await userAPI.createUser({
email: '[email protected]',
name: 'John Doe',
password: 'secure123',
preferences: {
theme: 'dark',
notifications: { email: true, push: false }
}
});
// Update user with partial data
await userAPI.patchUser({
name: 'John Smith',
preferences: { theme: 'light' }
});π€ Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
# Clone the repository
git clone https://github.com/azwebmaster/openapi-to-ts.git
cd openapi-to-ts
# Install dependencies
bun install
# Run tests
bun test
# Build the project
bun run buildπ License
MIT License - see LICENSE for details.
π Acknowledgments
- Built with ts-morph for powerful TypeScript manipulation
- Uses @apidevtools/swagger-parser for OpenAPI parsing
- Inspired by the TypeScript community's need for better API client generation
Made with β€οΈ for the TypeScript community
