npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@iamkvnn/swagger-ts-codegen

v1.0.1

Published

Generate TypeScript types and Axios services from OpenAPI/Swagger specs

Readme

swagger-ts-codegen

Generate TypeScript typesAxios service functions từ OpenAPI/Swagger specs (JSON hoặc YAML).

Tính năng

  • 🔄 YAML & JSON — hỗ trợ cả file .json, .yaml/.yml và URL trực tiếp
  • 🧩 Generic detection — tự nhận ApiResponseListX, ApiResponseX… → ApiResponse<T> và tách vào shared.ts
  • 📁 Output linh hoạt — types và services có thể xuất ra folder riêng nhau
  • 🏷️ Tag filter — chỉ generate những tag cần thiết (--include-tags, --exclude-tags)
  • 📄 Per-tag files — tách mỗi service thành file riêng (cart.service.ts, auth.service.ts…)
  • 🔤 Type prefix — thêm prefix vào tất cả type name (tránh conflict khi dùng nhiều service)
  • ⚙️ Config file — quản lý nhiều microservices trong 1 file codegen.config.json
  • 👁️ Watch mode — tự regenerate khi spec thay đổi (dành cho dev local)
  • 🎛️ Enum styleunion literals hoặc TypeScript enum
  • 📦 Params style — positional args hoặc destructured object (tương thích React Query)

Cài đặt

git clone <repo>
cd swagger-ts-codegen
npm install

Quick Start

# Từ file JSON
node src/cli.js -i api.json -o src/generated

# Từ file YAML
node src/cli.js -i api.yaml -o src/generated

# Từ URL (Swagger UI đang chạy)
node src/cli.js -i http://localhost:8080/v3/api-docs -o src/generated

Output Files

Mỗi lần generate tạo ra tối đa 3 loại file:

| File | Mô tả | |------|-------| | shared.ts | Generic wrapper types (ApiResponse<T>, PaginatedApiResponse<T>…) — không prefix, dùng chung | | types.ts | Tất cả concrete types/interfaces/enums — có prefix nếu dùng --prefix | | apiService.ts (hoặc {tag}.service.ts) | Axios instance + service objects theo từng tag |

shared.ts chỉ được tạo khi spec có generic wrapper types.


Tham số CLI đầy đủ

📥 Input

| Flag | Short | Mô tả | Bắt buộc | |------|-------|--------|----------| | --input | -i | Đường dẫn file hoặc URL đến OpenAPI spec (JSON/YAML) | ✅ (trừ khi dùng --config) | | --config | -c | Đường dẫn file config cho multi-service mode | ✅ (thay thế --input) |

📤 Output

| Flag | Short | Mô tả | Mặc định | |------|-------|--------|----------| | --output | -o | Thư mục output dự phòng cho tất cả file | ./generated | | --types-dir | | Thư mục riêng cho file types | giá trị --output | | --services-dir | | Thư mục riêng cho file service | giá trị --output | | --service-filename | | Tên file service. Dùng {tag} để tách thành nhiều file | apiService.ts | | --types-filename | | Tên file types (ví dụ: auth-types.ts) | types.ts | | --shared-filename | | Tên file shared types | shared.ts | | --ts-nocheck | | Thêm comment // @ts-nocheck/* eslint-disable */ ở đầu các file | không |

Ví dụ --service-filename:

# Một file duy nhất
--service-filename "apiService.ts"          # → apiService.ts

# Tách theo tag
--service-filename "{tag}.service.ts"       # → cart.service.ts, auth.service.ts…
--service-filename "{tag}Api.ts"            # → cartApi.ts, authApi.ts…

🔗 Import paths (khi dùng folder riêng)

| Flag | Mô tả | Mặc định | |------|--------|----------| | --types-import | Import path cho types.ts trong file service | Tự tính tương đối | | --shared-import | Import path cho shared.ts trong file service | Tự tính tương đối |

Khi nào cần dùng?

  • Khi project có path alias (@/, ~) thay vì path tương đối
  • Khi deploy file service vào vị trí khác với lúc generate
# Với TypeScript path alias
node src/cli.js -i api.json \
  --types-dir src/types \
  --services-dir src/services \
  --types-import "@/types/types" \
  --shared-import "@/types/shared"

🧬 Codegen

| Flag | Short | Giá trị | Mặc định | Mô tả | |------|-------|---------|----------|-------| | --enum | -e | union | enum | union | Kiểu enum | | --params | -p | individual | object | individual | Kiểu tham số hàm service | | --prefix | | string | (trống) | Prefix cho tất cả type names | | --include-tags | | string (comma-sep) | (tất cả) | Chỉ generate những tag này | | --exclude-tags | | string (comma-sep) | (không bỏ gì) | Bỏ qua những tag này |

Chi tiết --prefix:

  • Chỉ apply cho concrete types (CourseResponseCinxCourseResponse)
  • Không apply cho generic wrappers (ApiResponse<T> giữ nguyên)
  • Enum names cũng được prefix: CourseResponseLevelEnumCinxCourseResponseLevelEnum

Chi tiết --include-tags / --exclude-tags:

  • So sánh không phân biệt hoa/thường, bỏ qua -controller suffix
  • "cart" sẽ match tag cart-controller, Cart, cart
# Chỉ generate service cho cart và auth
--include-tags "cart,auth"

# Bỏ qua tag internal
--exclude-tags "internal,health,actuator"

⚡ Axios

| Flag | Giá trị | Mặc định | Mô tả | |------|---------|----------|-------| | --axios-import | string | (tự tạo) | Path import axios client có sẵn. Khi dùng, không generate axios setup | | --axios-client-name | string | apiClient | Tên biến axios client | | --axios-client-import | named | default | named | Kiểu import |

Ví dụ dùng axios client có sẵn:

# Named import: import { apiClient } from '@/lib/apiClient'
node src/cli.js -i api.json \
  --axios-import "@/lib/apiClient" \
  --axios-client-name "apiClient" \
  --axios-client-import "named"

# Default import: import myClient from '@/lib/apiClient'
node src/cli.js -i api.json \
  --axios-import "@/lib/apiClient" \
  --axios-client-name "myClient" \
  --axios-client-import "default"

🎮 Điều khiển

| Flag | Short | Mô tả | |------|-------|-------| | --only | | (chỉ với --config) Chỉ chạy một service theo name | | --watch | | Bật watch mode — poll spec và regenerate khi thay đổi | | --watch-interval | | Thời gian poll (ms). Mặc định: 3000 | | --dry-run | | Preview output, không ghi file | | --help | -h | Hiện help |


Enum Styles

--enum union (mặc định)

export interface CourseResponse {
  level?: "BEGINNER" | "INTERMEDIATE" | "ADVANCED";
  status?: "DRAFT" | "PUBLISHED" | "ARCHIVED";
}

--enum enum

Enum được hoist thành named export riêng:

export enum CourseResponseLevelEnum {
  BEGINNER = "BEGINNER",
  INTERMEDIATE = "INTERMEDIATE",
  ADVANCED = "ADVANCED",
}

export interface CourseResponse {
  level?: CourseResponseLevelEnum;
}

Params Styles

--params individual (mặc định)

async getCourses(
  params?: { page?: number; size?: number; categoryId?: string },
  config?: AxiosRequestConfig
): Promise<ApiResponse<CourseResponse[]>>

async updateCourse(
  courseId: string,
  body: UpdateCourseRequest,
  config?: AxiosRequestConfig
): Promise<ApiResponse<CourseResponse>>

--params object

Phù hợp với React Query và khi có nhiều tham số:

async getCourses(
  { page, size, categoryId }: { page?: number; size?: number; categoryId?: string },
  config?: AxiosRequestConfig
): Promise<ApiResponse<CourseResponse[]>>

async updateCourse(
  { courseId, body }: { courseId: string; body: UpdateCourseRequest },
  config?: AxiosRequestConfig
): Promise<ApiResponse<CourseResponse>>

Watch Mode

Watch mode tự động theo dõi spec và regenerate khi nội dung thay đổi — không cần chạy lại lệnh thủ công.

Cách hoạt động:

  1. Load spec → tính MD5 hash → generate lần đầu
  2. Mỗi N giây: load lại spec → so sánh hash
  3. Nếu hash thay đổi → regenerate và in thông báo
  4. Nhấn Ctrl+C để dừng
# Watch single spec
node src/cli.js -i http://localhost:8080/v3/api-docs -o src/generated --watch

# Watch với interval 5 giây
node src/cli.js -i api.json -o src/generated --watch --watch-interval 5000

# Watch tất cả services trong config
node src/cli.js --config codegen.config.json --watch

Config File (Microservices)

Khi project có nhiều microservice, dùng codegen.config.json để quản lý tất cả trong một chỗ.

Tạo config file

{
  "services": [
    {
      "name": "auth",
      "input": "https://api.example.com/v3/api-docs/auth",
      "typesDir": "src/types/auth",
      "servicesDir": "src/services/auth",
      "typesImport": "@/types/auth/types",
      "sharedImport": "@/types/auth/shared",
      "axiosImport": "@/lib/apiClient",
      "axiosClientName": "apiClient",
      "paramsStyle": "object"
    },
    {
      "name": "cart",
      "input": "https://api.example.com/v3/api-docs/cart",
      "typesDir": "src/types/cart",
      "servicesDir": "src/services/cart",
      "typesImport": "@/types/cart/types",
      "sharedImport": "@/types/cart/shared",
      "includeTags": ["cart"],
      "paramsStyle": "individual"
    }
  ],
  "watchInterval": 3000
}

Các field trong mỗi service

| Field | Bắt buộc | Mô tả | |-------|----------|-------| | name | ✅ | Tên định danh service (dùng với --only) | | input | ✅ | File path hoặc URL đến OpenAPI spec | | output | | Thư mục output dự phòng | | typesDir | | Thư mục cho file types | | servicesDir | | Thư mục cho file service | | typesFilename | | Tên file types | | sharedFilename | | Tên file shared types | | typesImport | | Custom import path cho file types | | sharedImport | | Custom import path cho file shared | | serviceFilename | | Tên file service (hỗ trợ {tag}) | | prefix | | Prefix cho type names | | includeTags | | Mảng tag cần generate | | excludeTags | | Mảng tag cần bỏ qua | | enumStyle | | "union" hoặc "enum" | | paramsStyle | | "individual" hoặc "object" | | axiosImport | | Custom axios client import path | | axiosClientName | | Tên biến axios client | | axiosClientImport | | "named" hoặc "default" | | tsNoCheck | | Boolean. Nếu true, thêm disable type-checking vào đầu file |

Chạy config

# Chạy tất cả services
node src/cli.js --config codegen.config.json

# Chỉ chạy một service
node src/cli.js --config codegen.config.json --only auth

# Xem trước, không ghi file
node src/cli.js --config codegen.config.json --dry-run

# Watch tất cả services
node src/cli.js --config codegen.config.json --watch

Ví dụ thực tế

Single service — cơ bản

node src/cli.js -i http://localhost:8080/v3/api-docs -o src/generated

Single service — với path alias và separate folders

node src/cli.js \
  -i http://localhost:8080/v3/api-docs \
  --types-dir src/types \
  --services-dir src/services \
  --shared-import "@/types/shared" \
  --types-import "@/types/types" \
  --axios-import "@/lib/apiClient" \
  --params object

Per-tag service files

node src/cli.js \
  -i http://localhost:8080/v3/api-docs \
  --service-filename "{tag}.service.ts" \
  --types-dir src/types \
  --services-dir src/services
# Tạo ra: cart.service.ts, auth.service.ts, course.service.ts…

Prefix để tránh conflict (khi dùng nhiều service trong 1 project)

node src/cli.js -i http://auth-service/v3/api-docs -o src/generated/auth --prefix Auth
node src/cli.js -i http://cart-service/v3/api-docs -o src/generated/cart --prefix Cart
# AuthUserResponse, CartItemResponse — không bao giờ conflict

Gộp tất cả services và types vào chung folder (Flat folder layout)

Khi có nhiều microservice và bạn muốn tất cả các file code services được gen nằm chung trong thư mục src/services, còn tất cả các file types nằm chung trong thư mục src/types mà không bị ghi đè hay tạo thêm thư mục con, bạn chỉ định cụ thể các thuộc tính typesFilename, sharedFilename, và serviceFilename trong codegen.config.json như sau:

{
  "services": [
    {
      "name": "auth",
      "input": "https://api.example.com/v3/api-docs/auth",
      "typesDir": "src/types",
      "servicesDir": "src/services",
      "typesFilename": "auth.types.ts",
      "sharedFilename": "auth.shared.ts",
      "serviceFilename": "auth.service.ts"
    },
    {
      "name": "user",
      "input": "https://api.example.com/v3/api-docs/user",
      "typesDir": "src/types",
      "servicesDir": "src/services",
      "typesFilename": "user.types.ts",
      "sharedFilename": "user.shared.ts",
      "serviceFilename": "user.service.ts"
    }
  ]
}

Kết quả cấu trúc:

src/
├── services/
│   ├── auth.service.ts
│   └── user.service.ts
└── types/
    ├── auth.types.ts
    ├── auth.shared.ts
    ├── user.types.ts
    └── user.shared.ts

Lưu ý: Bộ sinh code sẽ tự động tính toán relative imports động (ví dụ: trong auth.service.ts sẽ import từ ../types/auth.shared../types/auth.types) mà không cần khai báo typesImport hay sharedImport thủ công.


Programmatic API

const { generate, generateBatch } = require('./src/index');

// Single generate
const result = await generate('http://localhost:8080/v3/api-docs', {
  outputDir: './src/generated',
  enumStyle: 'union',        // 'union' | 'enum'
  paramsStyle: 'object',     // 'individual' | 'object'
  prefix: '',                // '' | 'Auth' | 'Cart' | ...
  includeTags: ['cart'],     // [] = tất cả
  excludeTags: [],
  serviceFilename: 'apiService.ts',  // hoặc '{tag}.service.ts'
  typesFilename: 'types.ts',         // tên file concrete types
  sharedFilename: 'shared.ts',       // tên file generic types
  typesDir: null,            // null = dùng outputDir
  servicesDir: null,
  typesImport: null,         // null = tự tính
  sharedImport: null,
  dryRun: false,
  axiosImport: null,         // null = tự generate axios setup
  axiosClientName: 'apiClient',
  axiosClientImport: 'named',
  tsNoCheck: false,          // nếu true, chèn comment disabling check TS/eslint lên đầu file
});

// result.shared  — nội dung shared.ts
// result.types   — nội dung types.ts
// result.services — nội dung service(s) — string hoặc Map<tag, string>
// result.files   — Array<{ path: string, content: string }>

// Batch generate từ config
const { loadConfig } = require('./src/config');
const config = loadConfig('./codegen.config.json');
const results = await generateBatch(config, { dryRun: false });

Generic Detection

Wrapper schemas được tự động nhận diện theo tên và gom thành generic interface trong shared.ts:

| Schema name trong spec | Được resolve thành | |------------------------|-------------------| | ApiResponseListFoo | ApiResponse<Foo[]> | | ApiResponseFoo | ApiResponse<Foo> | | PaginatedApiResponseFoo | PaginatedApiResponse<Foo> |

shared.ts (không prefix):

export interface ApiResponse<T> {
  success?: boolean;
  message?: string;
  data?: T;
}

types.ts (có prefix nếu dùng --prefix):

export interface CourseResponse { ... }
export interface CartItemResponse { ... }

service file import từ cả 2:

import type { ApiResponse } from './shared';
import type { CourseResponse, CartItemResponse } from './types';