openapi

mgd34msu's avatarfrom mgd34msu

Defines and generates OpenAPI 3.1 specifications with TypeScript type generation, validation, and documentation. Use when documenting APIs, generating client SDKs, or implementing contract-first API design.

⭐0stars🔀0forks📁View on GitHub🕐Updated Jan 4, 2026

When & Why to Use This Skill

This Claude skill empowers developers to define, generate, and manage OpenAPI 3.1 specifications with seamless TypeScript integration. It facilitates contract-first API design by automating type generation, schema validation, and interactive documentation, ensuring high consistency and type safety between backend services and frontend clients.

Use Cases

  • Contract-First Development: Designing detailed API specifications before writing code to ensure alignment between frontend and backend teams.
  • Type-Safe Client Generation: Automatically generating TypeScript interfaces and fetch clients to eliminate manual type definitions and reduce runtime errors.
  • Automated Documentation: Creating interactive Swagger UI or Redoc documentation directly from OpenAPI YAML/JSON files for better developer experience.
  • Request & Response Validation: Implementing middleware in frameworks like Express to automatically validate incoming requests and outgoing responses against the API schema.
  • Schema-Driven Development: Using Zod to define schemas and automatically exporting them to OpenAPI specifications to keep code and documentation in sync.
nameopenapi
descriptionDefines and generates OpenAPI 3.1 specifications with TypeScript type generation, validation, and documentation. Use when documenting APIs, generating client SDKs, or implementing contract-first API design.

OpenAPI

OpenAPI Specification (OAS) is a standard for describing REST APIs. It enables documentation, code generation, and validation.

Quick Start

OpenAPI Document

# openapi.yaml
openapi: 3.1.0
info:
  title: My API
  version: 1.0.0
  description: A sample API

servers:
  - url: https://api.example.com/v1
    description: Production
  - url: http://localhost:3000/v1
    description: Development

paths:
  /users:
    get:
      summary: List users
      operationId: listUsers
      tags: [Users]
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/LimitParam'
      responses:
        '200':
          description: List of users
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
                  pagination:
                    $ref: '#/components/schemas/Pagination'

    post:
      summary: Create user
      operationId: createUser
      tags: [Users]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserInput'
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'

  /users/{id}:
    get:
      summary: Get user by ID
      operationId: getUser
      tags: [Users]
      parameters:
        - $ref: '#/components/parameters/UserIdParam'
      responses:
        '200':
          description: User details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          $ref: '#/components/responses/NotFound'

components:
  schemas:
    User:
      type: object
      required: [id, email, createdAt]
      properties:
        id:
          type: string
          example: usr_abc123
        email:
          type: string
          format: email
        name:
          type: string
        createdAt:
          type: string
          format: date-time

    CreateUserInput:
      type: object
      required: [email]
      properties:
        email:
          type: string
          format: email
        name:
          type: string
          minLength: 1
          maxLength: 100

    Pagination:
      type: object
      properties:
        page:
          type: integer
        limit:
          type: integer
        total:
          type: integer

    Error:
      type: object
      required: [error, message]
      properties:
        error:
          type: string
        message:
          type: string

  parameters:
    UserIdParam:
      name: id
      in: path
      required: true
      schema:
        type: string

    PageParam:
      name: page
      in: query
      schema:
        type: integer
        default: 1

    LimitParam:
      name: limit
      in: query
      schema:
        type: integer
        default: 20
        maximum: 100

  responses:
    BadRequest:
      description: Bad request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

security:
  - BearerAuth: []

TypeScript Type Generation

Using openapi-typescript

npm install -D openapi-typescript
npx openapi-typescript ./openapi.yaml -o ./types/api.d.ts

Generated Types

// types/api.d.ts (generated)
export interface paths {
  "/users": {
    get: operations["listUsers"];
    post: operations["createUser"];
  };
  "/users/{id}": {
    get: operations["getUser"];
  };
}

export interface components {
  schemas: {
    User: {
      id: string;
      email: string;
      name?: string;
      createdAt: string;
    };
    CreateUserInput: {
      email: string;
      name?: string;
    };
  };
}

export interface operations {
  listUsers: {
    parameters: {
      query?: {
        page?: number;
        limit?: number;
      };
    };
    responses: {
      200: {
        content: {
          "application/json": {
            data: components["schemas"]["User"][];
            pagination: components["schemas"]["Pagination"];
          };
        };
      };
    };
  };
}

Type-Safe Fetch Client

npm install openapi-fetch
import createClient from 'openapi-fetch'
import type { paths } from './types/api'

const client = createClient<paths>({
  baseUrl: 'https://api.example.com/v1',
  headers: {
    Authorization: `Bearer ${token}`
  }
})

// Fully typed request and response
const { data, error } = await client.GET('/users', {
  params: {
    query: { page: 1, limit: 20 }
  }
})

// data is typed as { data: User[], pagination: Pagination }

const { data: user } = await client.POST('/users', {
  body: {
    email: 'user@example.com',
    name: 'John'
  }
})

// user is typed as User

Schema Validation

Using Zod with OpenAPI

npm install zod @anatine/zod-openapi
import { z } from 'zod'
import { extendZodWithOpenApi } from '@anatine/zod-openapi'

extendZodWithOpenApi(z)

const UserSchema = z.object({
  id: z.string().openapi({ example: 'usr_abc123' }),
  email: z.string().email(),
  name: z.string().optional(),
  createdAt: z.string().datetime()
}).openapi('User')

const CreateUserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1).max(100).optional()
}).openapi('CreateUserInput')

Generate OpenAPI from Zod

import { generateOpenApi } from '@anatine/zod-openapi'

const document = generateOpenApi({
  info: {
    title: 'My API',
    version: '1.0.0'
  },
  paths: {
    '/users': {
      post: {
        requestBody: {
          content: {
            'application/json': { schema: CreateUserSchema }
          }
        },
        responses: {
          201: {
            content: {
              'application/json': { schema: UserSchema }
            }
          }
        }
      }
    }
  }
})

Request Validation

Express Middleware

npm install express-openapi-validator
import express from 'express'
import * as OpenApiValidator from 'express-openapi-validator'

const app = express()

app.use(express.json())

app.use(
  OpenApiValidator.middleware({
    apiSpec: './openapi.yaml',
    validateRequests: true,
    validateResponses: true
  })
)

// Routes are automatically validated against the spec
app.post('/users', (req, res) => {
  // req.body is validated against CreateUserInput schema
  const user = createUser(req.body)
  res.status(201).json(user)
})

// Error handler for validation errors
app.use((err, req, res, next) => {
  if (err.status === 400) {
    return res.status(400).json({
      error: 'VALIDATION_ERROR',
      message: err.message,
      details: err.errors
    })
  }
  next(err)
})

Documentation UI

Swagger UI

npm install swagger-ui-express
import swaggerUi from 'swagger-ui-express'
import YAML from 'yamljs'

const openApiDocument = YAML.load('./openapi.yaml')

app.use('/docs', swaggerUi.serve, swaggerUi.setup(openApiDocument, {
  customCss: '.swagger-ui .topbar { display: none }',
  customSiteTitle: 'My API Docs'
}))

Redoc

import express from 'express'

app.get('/docs', (req, res) => {
  res.send(`
    <!DOCTYPE html>
    <html>
      <head>
        <title>API Docs</title>
        <link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
        <style>body { margin: 0; padding: 0; }</style>
      </head>
      <body>
        <redoc spec-url='/openapi.yaml'></redoc>
        <script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"></script>
      </body>
    </html>
  `)
})

app.get('/openapi.yaml', (req, res) => {
  res.sendFile('./openapi.yaml', { root: __dirname })
})

Code Generation

Generate API Client

# Using openapi-generator
npm install -g @openapitools/openapi-generator-cli

openapi-generator-cli generate \
  -i openapi.yaml \
  -g typescript-fetch \
  -o ./generated/client

# Using openapi-typescript-codegen
npm install -D openapi-typescript-codegen

npx openapi-typescript-codegen \
  --input ./openapi.yaml \
  --output ./generated/client \
  --client fetch

Generate Server Stubs

openapi-generator-cli generate \
  -i openapi.yaml \
  -g typescript-express-server \
  -o ./generated/server

Advanced Patterns

Discriminated Unions

components:
  schemas:
    Event:
      oneOf:
        - $ref: '#/components/schemas/UserCreatedEvent'
        - $ref: '#/components/schemas/UserDeletedEvent'
      discriminator:
        propertyName: type
        mapping:
          user.created: '#/components/schemas/UserCreatedEvent'
          user.deleted: '#/components/schemas/UserDeletedEvent'

    UserCreatedEvent:
      type: object
      required: [type, user]
      properties:
        type:
          type: string
          enum: [user.created]
        user:
          $ref: '#/components/schemas/User'

    UserDeletedEvent:
      type: object
      required: [type, userId]
      properties:
        type:
          type: string
          enum: [user.deleted]
        userId:
          type: string

Nullable Fields (3.1)

# OpenAPI 3.1 uses JSON Schema null type
name:
  type: ['string', 'null']

# With oneOf
name:
  oneOf:
    - type: string
    - type: 'null'

File Uploads

/upload:
  post:
    requestBody:
      content:
        multipart/form-data:
          schema:
            type: object
            properties:
              file:
                type: string
                format: binary
              description:
                type: string

Webhooks (3.1)

webhooks:
  orderCreated:
    post:
      summary: Order created webhook
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderEvent'
      responses:
        '200':
          description: Webhook processed

Best Practices

  1. Use $ref - Reuse schemas, parameters, responses
  2. Version your API - Include in path or server URL
  3. Document errors - Define all error responses
  4. Add examples - Include realistic example values
  5. Use operationId - Required for code generation
  6. Validate requests and responses - Catch bugs early
  7. Keep spec in sync - Generate from code or validate against it
  8. Use tags - Organize endpoints by domain

References