@spoosh/openapi
v0.2.1
Published
OpenAPI schema generator for Spoosh API definitions
Maintainers
Readme
@spoosh/openapi
Bidirectional conversion between Spoosh TypeScript schemas and OpenAPI 3.0/3.1 specifications.
Documentation · Requirements: TypeScript >= 5.0
Installation
npm install @spoosh/openapiFeatures
- Export: Generate OpenAPI 3.0 or 3.1 specs from TypeScript Spoosh schemas
- Import: Generate TypeScript Spoosh schemas from OpenAPI 3.0/3.1 specs
- JSON & YAML: Support for both JSON and YAML OpenAPI formats
- Type-safe: Path-based schema with
{ data; body?; query?; error? }structure - Error Types: Extract error types from 4xx/5xx responses
- JSDoc Preservation: Convert OpenAPI descriptions to TypeScript JSDoc comments
- File Uploads: Automatic File type detection for binary formats
Usage
Export: Spoosh → OpenAPI
Generate OpenAPI specifications from your TypeScript Spoosh schema:
# Basic usage
npx spoosh-openapi export -s ./src/schema.ts -o openapi.json
# With custom options
npx spoosh-openapi export \
--schema ./src/api-schema.ts \
--type MyApiSchema \
--output ./docs/openapi.json \
--title "My API" \
--version "2.0.0" \
--base-url "https://api.example.com"Schema File
// src/schema.ts
interface User {
id: number;
name: string;
email: string;
}
interface CreateUserBody {
name: string;
email: string;
}
export type ApiSchema = {
users: {
GET: { data: User[]; query: { page?: number; limit?: number } };
POST: { data: User; body: CreateUserBody };
};
"users/:id": {
GET: { data: User };
PUT: { data: User; body: Partial<CreateUserBody> };
DELETE: { data: void };
};
health: {
GET: { data: { status: string } };
};
};Import: OpenAPI → Spoosh
Generate TypeScript Spoosh schemas from existing OpenAPI specifications:
# Import from JSON
npx spoosh-openapi import openapi.json -o ./src/schema.ts --include-imports
# Import from YAML
npx spoosh-openapi import openapi.yaml -o ./src/schema.ts --include-imports
# Custom options
npx spoosh-openapi import \
./docs/openapi.json \
--output ./src/api-schema.ts \
--type-name MyApiSchema \
--include-imports \
--jsdocInput: OpenAPI Spec
{
"openapi": "3.0.0",
"paths": {
"/posts": {
"get": {
"description": "Retrieve all posts",
"parameters": [
{ "name": "userId", "in": "query", "schema": { "type": "integer" } }
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "array",
"items": { "$ref": "#/components/schemas/Post" }
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"Post": {
"type": "object",
"required": ["id", "title"],
"properties": {
"id": { "type": "integer" },
"title": { "type": "string" },
"desc": { "type": "string" }
}
}
}
}
}Generated Output
type Post = {
id: number;
title: string;
desc?: string;
};
type ApiSchema = {
posts: {
/** Retrieve all posts */
GET: { data: Post[]; query: { userId?: number } };
};
};CLI Options
Export Command
npx spoosh-openapi export [options]| Option | Alias | Required | Default | Description |
| ------------------- | ----- | -------- | ----------- | ----------------------------------------- |
| --schema | -s | Yes | - | Path to TypeScript file containing schema |
| --type | -t | No | ApiSchema | Name of the schema type to use |
| --output | -o | No | stdout | Output file path |
| --title | - | No | - | API title for OpenAPI info |
| --version | - | No | 1.0.0 | API version for OpenAPI info |
| --base-url | - | No | - | Base URL for servers array |
| --openapi-version | - | No | 3.1.0 | OpenAPI spec version (3.0.0 or 3.1.0) |
Import Command
npx spoosh-openapi import <input> [options]| Option | Alias | Required | Default | Description |
| ------------------- | ----- | -------- | ----------- | -------------------------------------------------------------- |
| <input> | - | Yes | - | Path to OpenAPI spec (JSON or YAML) |
| --output | -o | Yes | - | Output TypeScript file path |
| --type-name | -t | No | ApiSchema | Schema type name |
| --include-imports | - | No | false | Include Spoosh type imports |
| --jsdoc | - | No | false | Include JSDoc comments from OpenAPI descriptions and summaries |
Programmatic Usage
Export API
import { parseSchema, generateOpenAPISpec } from "@spoosh/openapi";
const { endpoints, schemas } = parseSchema("./src/schema.ts", "ApiSchema");
const spec = generateOpenAPISpec(endpoints, schemas, {
title: "My API",
version: "1.0.0",
baseUrl: "https://api.example.com",
});
console.log(JSON.stringify(spec, null, 2));Import API
import {
importOpenAPISpec,
loadOpenAPISpec,
generateSpooshSchema,
} from "@spoosh/openapi";
// High-level API (load + generate)
const tsCode = importOpenAPISpec("./openapi.json", {
typeName: "ApiSchema",
includeImports: true,
jsdoc: true,
});
// Or use low-level APIs
const spec = loadOpenAPISpec("./openapi.json");
const schema = generateSpooshSchema(spec, {
typeName: "ApiSchema",
includeImports: true,
});
console.log(schema);Type Detection
The import feature generates endpoint types with appropriate fields:
| OpenAPI Pattern | Spoosh Type |
| ------------------------------------------------ | -------------------------------- |
| Query parameters | { data: TData; query: TQuery } |
| multipart/form-data request body | { data: TData; body: TBody } |
| application/json request body | { data: TData; body: TBody } |
| application/x-www-form-urlencoded request body | { data: TData; body: TBody } |
| No response body (204) | { data: void } |
| Simple response only | { data: TData } |
Error Type Extraction
Error types are automatically extracted from 4xx and 5xx response schemas. If a response only has a description without a schema, no error type is added.
{
"responses": {
"200": {
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/User" }
}
}
},
"400": {
"description": "Bad request"
},
"500": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"system_message": { "type": "string" }
}
}
}
}
}
}
}Generated types:
// Only 500 has a schema, so only that is included
POST: {
data: User;
body: CreateUserBody;
error: { system_message?: string };
};
// If no error responses have schemas, no error type is added
GET: { data: User };Multiple error schemas are automatically unioned:
// 400 and 500 both have schemas
POST: {
data: User;
body: Body;
error: { error?: string } | { system_message?: string };
};License
MIT
