specjet generate Command Reference

The generate command creates TypeScript types and API client code from your OpenAPI contract.

Basic Usage

specjet generate [options]

Examples

Basic Generation

# Generate types and client from api-contract.yaml
specjet generate

# Output:
# βœ… Generation complete!
#    Types: src/types/api.ts (4 interfaces)
#    Client: src/api/client.ts (5 methods)
#    Documentation: SPECJET_USAGE.md

Watch Mode for Development

# Auto-regenerate when contract changes
specjet generate --watch

# Perfect for iterative API design
# Edit api-contract.yaml and see changes instantly

Generate with Mock Server

# Generate types and API client
specjet generate

# Files are created in:
# src/types/api.ts
# src/api/client.ts

Custom Output Directory

# Generate to custom location
specjet generate --output ./generated

# Files created in:
# ./generated/types/
# ./generated/api/

Command Options

Option Description Default
--watch Watch contract file for changes and auto-regenerate false
--output <dir> Custom output directory From config
--config <path> Custom configuration file ./specjet.config.js
--verbose Show detailed generation process false

Generated Files

TypeScript Interfaces (src/types/api.ts)

Generated from OpenAPI schemas with full type safety:

// Generated from components.schemas in your contract
export interface User {
  id: number;
  name: string;
  email: string;
  isActive?: boolean;  // Optional because not in required array
  createdAt: string;   // format: date-time becomes string
}

export interface CreateUserRequest {
  name: string;
  email: string;
  isActive?: boolean;
}

export interface UpdateUserRequest {
  name?: string;       // All fields optional for PATCH
  email?: string;
  isActive?: boolean;
}

// Array and pagination types
export interface PaginatedUsers {
  data: User[];
  page: number;
  limit: number;
  total: number;
}

API Client (src/api/client.ts)

Type-safe API client with methods for each operation:

export class ApiClient {
  constructor(baseUrl: string = 'http://localhost:3001') {
    this.baseUrl = baseUrl;
  }

  // Authentication methods
  setApiKey(key: string): ApiClient;
  setBearerToken(token: string): ApiClient;
  setBasicAuth(username: string, password: string): ApiClient;

  // Generated API methods (from operationId)
  async getUsers(params?: GetUsersParams): Promise<User[]>;
  async createUser(data: CreateUserRequest): Promise<User>;
  async getUserById(id: number): Promise<User>;
  async updateUser(id: number, data: UpdateUserRequest): Promise<User>;
  async deleteUser(id: number): Promise<void>;
}

// Parameter types for query parameters
export interface GetUsersParams {
  page?: number;
  limit?: number;
  search?: string;
}

Mock Server

SpecJet provides a built-in mock server via the specjet mock command. No code generation required - the mock server automatically reads your OpenAPI contract and provides realistic endpoints with generated data.

Usage Documentation (SPECJET_USAGE.md)

Auto-generated guide with examples specific to your contract:

# API Usage Guide

## Available Operations

### Users API

#### Get All Users
```typescript
const users = await api.getUsers({ page: 1, limit: 20 });

Create User

const newUser = await api.createUser({
  name: "John Doe",
  email: "john@example.com"
});

## Type Mapping Rules

SpecJet converts OpenAPI schemas to TypeScript using these rules:

### Primitive Types
| OpenAPI | TypeScript | Notes |
|---------|------------|-------|
| `string` | `string` | |
| `integer` | `number` | |
| `number` | `number` | |
| `boolean` | `boolean` | |
| `array` | `T[]` | Uses items type |
| `object` | `interface` | Named interface |

### String Formats
| Format | TypeScript | Example |
|--------|------------|---------|
| `date` | `string` | `"2023-01-01"` |
| `date-time` | `string` | `"2023-01-01T12:00:00Z"` |
| `email` | `string` | Runtime validation |
| `uri` | `string` | Runtime validation |
| `uuid` | `string` | Runtime validation |

### Advanced Types
```yaml
# Enum becomes union type
enum: [active, inactive, pending]
# Becomes: 'active' | 'inactive' | 'pending'

# oneOf becomes union of interfaces
oneOf:
  - $ref: '#/components/schemas/User'
  - $ref: '#/components/schemas/AdminUser'
# Becomes: User | AdminUser

# allOf becomes intersection
allOf:
  - $ref: '#/components/schemas/BaseUser'
  - type: object
    properties:
      role: { type: string }
# Becomes: BaseUser & { role: string }

Watch Mode Details

Watch mode monitors your contract file and auto-regenerates when changes are detected:

specjet generate --watch

Features:

  • Debounced regeneration (500ms delay)
  • Only regenerates on actual changes
  • Preserves running processes
  • Shows diff of changes made
  • Graceful error handling

Example watch session:

πŸ” Watching for changes to api-contract.yaml...

πŸ“ Contract changed, regenerating...
βœ… Types updated (added 1 interface)
βœ… Client updated (added 1 method)

πŸ” Watching for changes...

πŸ“ Contract changed, regenerating...
❌ Generation failed: Invalid schema at line 45
   Fix the error and save to try again

πŸ” Watching for changes...

Configuration Integration

The generate command respects all configuration from specjet.config.js:

export default {
  // Input contract
  contract: './api-contract.yaml',
  
  // Output paths (used by --output override)
  output: {
    types: './src/types',
    client: './src/api'
  },
  
  // TypeScript generation options
  typescript: {
    strictMode: true,          // Enable strict null checks
    exportType: 'named',       // 'named' | 'default' | 'namespace'
    clientName: 'ApiClient',   // Generated client class name
    enumType: 'union',         // 'union' | 'enum'
    dateType: 'string',        // 'string' | 'Date'
    additionalProperties: false // Strict object types
  }
};

TypeScript Options Explained

strictMode: Controls TypeScript strict settings

// strictMode: true
interface User {
  id: number;
  name: string;
  optional?: string | undefined;  // Explicit undefined
}

// strictMode: false  
interface User {
  id: number;
  name: string;
  optional?: string;  // May be undefined
}

exportType: Controls how types are exported

// exportType: 'named' (default)
export interface User { ... }
export class ApiClient { ... }

// exportType: 'default'
interface User { ... }
class ApiClient { ... }
export { User, ApiClient };

// exportType: 'namespace'
export namespace Api {
  export interface User { ... }
  export class Client { ... }
}

enumType: Controls enum generation

# OpenAPI enum
status:
  type: string
  enum: [active, inactive, pending]
// enumType: 'union' (default)
type Status = 'active' | 'inactive' | 'pending';

// enumType: 'enum'
enum Status {
  Active = 'active',
  Inactive = 'inactive', 
  Pending = 'pending'
}

Error Handling

The generate command provides detailed error messages for common issues:

Contract Validation Errors

❌ Contract validation failed:
   Line 23: Property 'type' is required for schema 'User'
   Line 45: Invalid reference '$ref: #/components/schemas/Missing'
   Line 67: Duplicate operationId 'getUsers'

πŸ’‘ Fix these errors in api-contract.yaml and run generate again

TypeScript Generation Errors

❌ TypeScript generation failed:
   Schema 'User' has circular reference
   Schema 'Product' uses unsupported type 'file'

πŸ’‘ Check your schema definitions for circular references
πŸ’‘ File uploads are not yet supported

File System Errors

❌ Cannot write to output directory:
   Permission denied: ./src/types/

πŸ’‘ Run: chmod 755 ./src/types/
πŸ’‘ Or change output directory in specjet.config.js

Performance Considerations

Large Contracts

For contracts with many schemas and endpoints:

# Check generation performance
time specjet generate --verbose

# Output shows timing breakdown:
# Contract parsing: 234ms
# Type generation: 456ms  
# Client generation: 123ms
# File writing: 67ms
# Total: 880ms

Watch Mode Optimization

  • Uses efficient file watching (no polling)
  • Debounces rapid changes (500ms)
  • Only regenerates changed parts when possible
  • Memory efficient for long-running sessions

Generated Code Size

Typical output sizes:

  • Small API (5 schemas, 10 endpoints): ~50KB
  • Medium API (20 schemas, 50 endpoints): ~200KB
  • Large API (100 schemas, 200 endpoints): ~1MB

Integration with Build Tools

Package.json Scripts

{
  "scripts": {
    "predev": "specjet generate",
    "dev": "concurrently \"specjet generate --watch\" \"npm run start\"",
    "prebuild": "specjet generate",
    "type-check": "tsc --noEmit src/types/api.ts"
  }
}

CI/CD Integration

# GitHub Actions example
- name: Generate API types
  run: |
    npm install -g specjet
    specjet generate
    
- name: Verify types compile
  run: |
    npx tsc --noEmit src/types/api.ts
    
- name: Check for uncommitted changes
  run: |
    git diff --exit-code src/types/ src/api/

Troubleshooting

Common Issues

Generated files not found after running generate:

# Check if command completed successfully
echo $?  # Should be 0

# Verify output paths
specjet generate --verbose

TypeScript compiler errors with generated types:

# Check TypeScript version (needs 4.5+)
npx tsc --version

# Verify tsconfig.json includes generated files
cat tsconfig.json | grep -A 5 '"include"'

Watch mode not detecting changes:

# Check file permissions
ls -la api-contract.yaml

# Try manual regeneration
specjet generate --verbose

Generated client doesn’t match contract:

# Verify contract is valid
specjet validate api-contract.yaml

# Clear generated files and regenerate
rm -rf src/types src/api
specjet generate

Debug Mode

# Enable verbose logging
specjet generate --verbose

# Shows detailed process:
# πŸ“– Parsing contract: api-contract.yaml
# πŸ” Found 5 schemas: User, Product, Order, Payment, Address
# πŸ” Found 12 endpoints across 4 paths
# πŸ”§ Generating User interface...
# πŸ”§ Generating Product interface...
# ...
  • init: Initialize project and create initial contract
  • mock: Start mock server using generated code
  • validate: Validate contract syntax and completeness

Next Steps

After generating your types and client:

  1. Start Mock Server: specjet mock to test with realistic data
  2. Use in Application: Import and use the generated types and client
  3. Set Up Watch Mode: Use --watch for rapid development cycles
  4. Learn Best Practices: See Best Practices Guide
  5. Framework Integration: Check Integration Guides

Copyright © 2025 SpecJet. Open source CLI for API contract development.