home / skills / timbenniks / timbenniks-agent-skills / openapi-typescript-sdk-generator

openapi-typescript-sdk-generator skill

/skills/openapi-typescript-sdk-generator

This skill generates a production-grade TypeScript SDK from an OpenAPI spec, with deterministic output, human-friendly method names, and interactive

npx playbooks add skill timbenniks/timbenniks-agent-skills --skill openapi-typescript-sdk-generator

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
11.8 KB
---
name: openapi-typescript-sdk-generator
description: Generate a production TypeScript SDK from an OpenAPI 3.0/3.1 spec (URL or local file), with human-friendly method names, interactive confirmation, and deterministic output. Use when the user wants a type-safe, fetch-based SDK or a drop-in client. Do not use for streaming/SSE/WebSockets or interactive OAuth flows.
---

# OpenAPI TypeScript SDK generator

Generate a production-quality TypeScript SDK from an OpenAPI specification.
Behave like a real SDK generator, not a thin OpenAPI wrapper.

## Scope and guarantees

- **Analyze the OpenAPI spec first** to propose intelligent defaults based on its contents
- Propose sensible defaults derived from the spec (title, servers, security schemes, operations, etc.)
- Ask required questions and require explicit confirmation
- Derive human-friendly method names from context, not OpenAPI identifiers
- Produce deterministic output
- Support OpenAPI 3.0 and 3.1
- Generate a typed ApiError and runtime features (retries, rate limiting, caching)
- Explain spec issues and tolerate non-blocking drift

## Inputs (prefill only)

If the user provides JSON, treat it as prefilled answers.
Still show defaults and require explicit confirmation before generating.

Example prefill:

```json
{
  "openapi_url": "https://api.example.com/openapi.yaml",
  "openapi_path": "C:/specs/openapi.yaml",
  "output_mode": "standalone_package | folder_only",
  "output_path": "sdk",
  "package_name": "@example/api-sdk",
  "client_name": "ExampleClient",
  "runtime_target": "node_and_browser",
  "node_version": "22",
  "auth_method": "bearer"
}
```

Either `openapi_url` or `openapi_path` must be provided or collected.

## Spec analysis (mandatory first step)

Before asking any questions, the agent must:

1. Load and parse the OpenAPI spec (from URL or file path)
2. Analyze the spec to extract:
   - `info.title` → for package/client naming
   - `info.version` → for package version suggestion
   - `servers` → for base URL defaults
   - `components.securitySchemes` → for auth method defaults
   - `security` (global and per-operation) → for auth method analysis
   - Operation patterns → for naming style suggestions
   - Response headers → for rate limiting/caching hints
   - Operation methods → for runtime target suggestions
3. Propose defaults based on this analysis
4. Show reasoning for each proposed default

## Mandatory interaction flow

1. **Parse and analyze the OpenAPI spec first** (if provided or collected)
   - Load the spec from URL or file path
   - Analyze the spec to propose intelligent defaults
   - Extract relevant information (title, servers, security schemes, operations, etc.)
2. Ask all required intake questions in one concise block.
3. **Show defaults for every question, proposing values derived from the OpenAPI spec analysis**
4. Require explicit confirmation of answers or defaults.
5. Show a naming preview and allow overrides.
6. Ask for a final confirmation gate before any code generation.

Do not generate code until the user explicitly confirms.

## Required intake questions (always ask)

Ask these questions in a single block and show defaults **proposed from the OpenAPI spec analysis**.

1. SDK identity
   - Package name  
     Default: derive from OpenAPI `info.title` (sanitized, lowercased, kebab-case), or `openapi-sdk` if unavailable
     Example: `"Pet Store API"` → `@pet-store/api-sdk` or `pet-store-api-sdk`
   - Exported client name  
     Default: derive from OpenAPI `info.title` (sanitized, PascalCase + "Client"), or `ApiClient` if unavailable
     Example: `"Pet Store API"` → `PetStoreClient`

2. Output
   - Output mode: `folder_only` or `standalone_package`  
     Default: `folder_only`
   - Output path (folder)  
     Default: `sdk/`

3. Spec source
   - OpenAPI URL or local file path  
     Default: use provided value; otherwise ask
   - If URL: does it require auth headers?  
     Default: no

4. Base URL
   - Default: first entry in OpenAPI `servers`
   - If no servers exist, default to empty string and warn

5. Naming style
   - Verb-first (`listPlants`, `getPlant`)
   - Resource-first (`plantsList`, `plantsGet`)  
     Default: verb-first

6. Runtime target
   - `node_only`, `browser_only`, or `node_and_browser`  
     Default: `node_and_browser`
   - Node version (if Node is included)  
     Default: `22`

7. Primary authentication method
   - API key
   - Bearer token
   - OAuth2 access token (passthrough only)
   - Basic auth
   - None  
     Default: analyze OpenAPI `security` and `components.securitySchemes` to propose the most common/primary auth method, or `none` if none exist
     - If multiple schemes exist, prefer: Bearer > API Key > OAuth2 > Basic > None
     - Show which operations use which auth methods if they differ

8. Integration tests
   - Yes, generate real integration tests (env-based, disabled by default)
   - No, generate mock-only tests  
     Default: no

## Naming preview step (mandatory)

Before generation:

- Show a preview of representative endpoints with proposed names.
- Allow user overrides.
- Proceed only after confirmation.
- Record overrides in `sdk-decisions.md`.

## Confirmation gate (mandatory)

After collecting answers and naming overrides, present a final summary and ask for explicit confirmation.

Example:

Here is what I am going to generate:

- Package name: `openapi-sdk`
- Client name: `ApiClient`
- Output mode: `folder_only`
- Output path: `sdk/`
- Base URL: `https://api.example.com`
- Naming style: verb-first
- Runtime target: node_and_browser (Node 22)
- Auth method: bearer token
- Integration tests: disabled

Reply with:

- `confirm` to proceed
- or list any changes you want

Do not generate code until the user confirms.

## Decision recording (mandatory)

After confirmation, write:

```
sdk-decisions.md
```

Record all final decisions and whether each one was explicit or default.

Example:

```md
- package_name: openapi-sdk (default, confirmed)
- client_name: ApiClient (default, confirmed)
- output_mode: folder_only (explicit)
- output_path: sdk/ (default, confirmed)
- naming_style: verb-first (default, confirmed)
- runtime_target: node_and_browser (default, confirmed)
- node_version: 22 (default, confirmed)
- integration_tests: false (default, confirmed)
```

## Output modes

### folder_only

Generate a minimal SDK folder suitable for copying into an existing codebase.

```
sdk/
├── index.ts
├── client.ts
├── operations.ts
├── errors.ts
├── types/
├── utils/
├── openapi-report.md
└── sdk-decisions.md
```

### standalone_package

Generate a full, publishable SDK project.

```
<package>/
├── package.json
├── tsconfig.json
├── tsdown.config.ts
├── README.md
├── src/
│   ├── index.ts
│   ├── client.ts
│   ├── operations.ts
│   ├── errors.ts
│   ├── types/
│   └── utils/
├── examples/
├── tests/
├── openapi-report.md
└── sdk-decisions.md
```

## Naming strategy (critical)

Do not use raw OpenAPI operationId values.

Derive names deterministically from context.

### Naming goals

- Human-friendly
- Stable across regenerations
- Flat function surface
- Predictable
- Collision-free

### Naming algorithm

1. Extract the primary resource from the path  
   Ignore version prefixes such as `/v1` or `/api`.

Examples:

- `/plants` → `plants`
- `/plants/{id}/events` → primary `plants`, secondary `events`

2. Infer the action from HTTP method and path shape

| Method | Path shape | Action |
| ------ | ---------- | ------ |
| GET    | collection | list   |
| GET    | item       | get    |
| POST   | collection | create |
| PUT    | item       | update |
| PATCH  | item       | update |
| DELETE | item       | remove |

3. Apply naming style

Verb-first:

- `listPlants`
- `getPlant`
- `updatePlant`
- `removePlant`
- `listPlantEvents`
- `createPlantEvent`

Resource-first:

- `plantsList`
- `plantsGet`
- `plantEventsList`

4. Singularize item resources

- Prefer `getPlant` over `getPlants`
- Use a small irregular map (`people` → `person`, `children` → `child`)
- If uncertain, keep plural and document it

5. Collision handling

- Prefer param-based disambiguation (`getPlantById`, `getPlantBySlug`)
- If unresolved, append a deterministic suffix (`__get`, `__post`)
- Document all collisions and resolutions in `openapi-report.md`

## OpenAPI validation and report

Validate the spec and tolerate non-blocking issues.

Generate:

```
openapi-report.md
```

Include:

- Blocking issues
- Non-blocking issues
- Why each issue matters
- What assumptions were made
- A mapping table of generated method names to original `operationId` (if present)

## SDK runtime behavior

### Transport

- Use native `fetch`
- Isomorphic (Node and browser where possible)
- ESM only

### Errors

Generate a typed ApiError with:

- status
- code
- message
- body
- headers
- method
- url

Throw ApiError for all non-2xx responses, except 304 handled by cache.

### Retries

- Retry on network errors, 429, and 5xx
- Default max attempts: 3
- Exponential backoff with jitter
- Honor `Retry-After`
- Allow per-request overrides
- Default to idempotent methods only; require explicit opt-in for POST/PATCH

### Rate limiting

- In-memory limiter per client instance
- Respect rate-limit headers and Retry-After

### Caching

- GET requests only by default
- In-memory cache with TTL
- Manual busting
- ETag / If-None-Match support
- Respect Cache-Control and Pragma
- Do not cache when Authorization is present unless explicitly enabled

## Integration tests (optional)

If enabled:

- Generate real integration tests
- Disabled by default in CI
- Credentials loaded from environment variables
- Tests perform simple read operations and validate response shape
- Required env vars documented in README

If disabled:

- Generate mock-based tests only

## Generated API surface

Each operation exports a flat async function:

```ts
listPlants(params, options?): Promise<Plant[]>
```

Options allow:

- Auth overrides
- Retry overrides
- Cache overrides
- AbortSignal
- Extra headers

## Determinism

- Sort operations by path + method for stable output
- Keep naming stable across regenerations
- Record decisions in `sdk-decisions.md`

## Acceptance criteria

Output is correct only if:

- All required questions were asked
- Defaults were shown and explicitly confirmed
- Code generation occurred only after confirmation
- Names were derived from context, not operationId
- Types compile under strict TypeScript
- Retry, cache, and rate limiting work as specified
- `openapi-report.md` and `sdk-decisions.md` exist
- Optional integration tests are safe and documented
- Output is deterministic

## Defaults (proposed from OpenAPI spec analysis)

The agent must analyze the OpenAPI spec and propose intelligent defaults:

- **Package name**: Derive from `info.title` (sanitized, kebab-case), fallback to `openapi-sdk`
- **Client name**: Derive from `info.title` (sanitized, PascalCase + "Client"), fallback to `ApiClient`
- **Base URL**: First entry in OpenAPI `servers` array, or empty string with warning if none
- **Auth method**: Analyze `security` and `components.securitySchemes` to propose primary method (prefer: Bearer > API Key > OAuth2 > Basic > None)
- **Naming style**: verb-first (unless spec patterns suggest resource-first)
- **Output mode**: folder_only
- **Output path**: sdk/ (or derive from package name if standalone_package)
- **Runtime target**: node_and_browser (analyze operations to suggest if browser-only or node-only would be more appropriate)
- **Node version**: 22
- **Cache enabled**: For GET requests (analyze spec to see if caching headers are used)
- **Retries**: Enabled for idempotent methods (analyze operations to determine idempotency)
- **Rate limiting**: Enabled (check if spec includes rate limit headers/documentation)
- **Integration tests**: Disabled

Always show the reasoning behind each proposed default based on the spec analysis.

Overview

This skill generates a production-quality TypeScript SDK from an OpenAPI 3.0 or 3.1 specification. It analyzes the spec first to propose deterministic, human-friendly method names, sensible defaults, and a fetch-based, type-safe client. Generation only runs after interactive intake, naming preview, and explicit confirmation.

How this skill works

First the skill loads and parses the OpenAPI spec (URL or local file) and extracts title, version, servers, security schemes, operations, and headers. It proposes defaults derived from that analysis, shows reasoning for each default, asks all required intake questions in one block, and presents a naming preview. The tool records final decisions in sdk-decisions.md and produces either a minimal SDK folder or a full standalone package with typed errors, retries, caching, and rate-limiting behavior.

When to use it

  • You want a type-safe, fetch-based TypeScript client derived from an OpenAPI 3.0/3.1 spec.
  • You need stable, human-friendly method names rather than raw operationId values.
  • You require deterministic, repeatable SDK output across regenerations.
  • You want built-in retries, rate limiting, caching, and a typed ApiError contract.
  • You need a drop-in SDK folder for an existing codebase or a full publishable package.

Best practices

  • Provide the OpenAPI spec URL or local path up front so defaults can be derived automatically.
  • Review the naming preview and override any ambiguous names before confirming generation.
  • Keep interactive OAuth flows, streaming/SSE/WebSockets out of scope—use alternative clients for those.
  • Enable integration tests only when safe credentials can be supplied via environment variables.
  • Review openapi-report.md for spec issues and confirm assumptions recorded in sdk-decisions.md.

Example use cases

  • Generate a pet-store SDK from a public openapi.yaml and publish it as an NPM package.
  • Create a minimal sdk/ folder to include in an existing monorepo with strict TypeScript checks.
  • Produce a client with built-in retries and ETag caching for a RESTful backend used by both Node and browser.
  • Audit an OpenAPI spec, get a report of non-blocking issues, and accept proposed naming and defaults before codegen.

FAQ

Will you generate code immediately after I provide the spec?

No. The skill analyzes the spec, proposes defaults, asks all intake questions, shows a naming preview, and waits for explicit confirmation before generating any code.

Does this support streaming endpoints or interactive OAuth flows?

No. Streaming/SSE/WebSockets and interactive OAuth flows are out of scope. OAuth2 access token passthrough is supported where the spec documents it.