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

@hyperzlib/koa-swagger-decorator

v2.2.5

Published

> defined your api with simple decorators and generate api docs automatically

Readme

@hyperzlib/koa-swagger-decorator

defined your api with simple decorators and generate api docs automatically

New features beyond Original swagger-decorator

  1. Allows applyRoute(controller: Class | instance) to support both class and instance as input, providing more flexibility in route registration.
  2. Allows @responses(z.any() | z.array(...) | z.string()) to support more flexible response schema definition.
  3. Automatically parse query params into correct types (especially for string, string[] and boolean) based on zod schema definition, improving request handling and validation.

Important

this docs is written for V2 and it's currently under development. refer to V1 Docs for V1 version

V2 version has undergone complete refactoring, introducing break change and new APIs to provide more type-safe functionality.

Installation

npm i koa-swagger-decorator@next

Introduction

Developing your type-safe API using simple decorators and zod schema with auto-generated OpenAPI docs based on OpenAPI V3.

Usage

Quick Example

// define your api handler with @routeConfig decorator and it will generate OpenAPI Docs automatically
class UserController {
  @routeConfig({ // define your API route info using @routeConfig decorator
    method: "post",
    path: "/users",
    summary: "create a user",
    tags: ["USER"],
    operationId: "CreateUser",
  })
  @body(z.object({uid: z.string(), name: z.string(), age: z.number().min(18).optional()}))
  async CreateUser(ctx: Context, args) {
    // body params will be validated using zodSchema.parse(ctx.request.body)
    // and assigned the parsed value to args.
    console.log(args, args.body.uid, args.body.name);
    ctx.body = { message: "create", id: "123" } as ICreateUserRes;
  }
}

Runnable Example

you can refer to example dir for details.

git clone https://github.com/Cody2333/koa-swagger-decorator.git
cd koa-swagger-decorator
npm i
npm run dev

// open http://localhost:3000/api/swagger-html to execute api
// open example dir for detail codes.

Typescript Configuration

typescript is required. Please make sure compilerOptions is set correctly in tsconfig.json

// tsconfig.json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "esModuleInterop": true,
  }
}

Integrate with Koa

following below steps to integrate your koa application with koa-swagger-decorator

  1. Define your Request/Response with Zod Schema
// file -> ./schema/user.ts
import { z } from 'koa-swagger-decorator'
// define req/res schema
const CreateUserReq = z.object({
  uid: z.string().nonempty(),
  name: z.string().nullable().optional(),
  age: z.number().min(18).nullable(),
  operator: z.string().nonempty().optional(),
});

const CreateUserRes = z.object({
  id: z.string().nullable(),
  message: z.string().nullable(),
});

// export req/res typings
export type ICreateUserRes = z.infer<typeof CreateUserRes>;
export type ICreateUserReq = z.infer<typeof CreateUserReq>;

You can also use zod v3 from installed package.

npm i zod@^3.0.0
import { z } from "zod";
// define req/res schema
const CreateUserReq = z.object({
  uid: z.string().nonempty(),
  name: z.string().nullable().optional(),
  age: z.number().min(18).nullable(),
  operator: z.string().nonempty().optional(),
});
// ... same as above
  1. Write your API Handler with decorator and zod schema
// file -> ./controller/user.ts
import { Context } from "koa";
import { body, responses, routeConfig } from "../../lib/decorator";
import {
  CreateUserReq,
  CreateUserRes,
} from "../schemas/user";
import { ParsedArgs, z } from "../../lib";

class UserController {
 
  @routeConfig({ // define your API route info using @routeConfig decorator
    method: "post",
    path: "/users",
    summary: "create a user",
    tags: ["USER"],
    operationId: "CreateUser",
  })
  @body(CreateUserReq)
  @responses(CreateUserRes)
  async CreateUser(ctx: Context, args: ParsedArgs<ICreateUserReq>) {
    // args is injected with values = CreateUserReq.parse(ctx.request.body)
    console.log(args, args.body.uid, args.body.name);
    ctx.body = { message: "create", id: "123" } as ICreateUserRes;
  }

}

export { UserController };
  1. Init SwaggerRouter Instance
// file -> ./routes/index.ts
import { SwaggerRouter } from 'koa-swagger-decorator'
import { UserController } from './controller/user'

const router = new SwaggerRouter({
  spec: {
    info: {
      title: "Example API Server",
      version: "v1.0",
    },
  },
  swaggerHtmlEndpoint: '/swagger-html',
  swaggerJsonEndpoint: '/swagger-json',
});

// apply swagger docs routes
router.swagger();

// register user defined routes implementation
router
  // class mode: a new controller instance will be created for each request
  .applyRoute(UserController)
  // instance mode: reuse an existing controller instance
  // .applyRoute(new UserController())
  // .applyRoute(DemoController); // chained for more then one controller imports

export {router}
  1. Init Koa Application
// file -> ./main.ts
import {router} from './routes/index'
const app = new Koa();
app
  .use(cors())
  .use(bodyParser())
  .use(router.routes())
  .use(router.allowedMethods());

export default app.listen(config.port, () => {
  console.log(`App is listening on ${config.port}.`);
});

// running ts-node ./main.ts and that's all

Define query/path params

@routeConfig({
  method: "get",
  path: "/user/{uid}",
  summary: "get user by id",
  description: "detailed user",
  tags: ["USER"],
  operationId: "GetUserById",
  request: {
    params: z.object({
      uid: z.string().nonempty(), // path params, don't forget to add {uid} in [path] field.
    }),
    query: z.object({
      count: z.coerce.number().default(10), // using z.coerce to convert query string into number & validate
      limit: z.coerce.number().default(0),
      includeDeleted: z.boolean().optional(),
      tags: z.array(z.string()).optional(),
    })
  },
})

koa-swagger-decorator will preprocess ctx.request.query before zod parsing based on your query schema shape:

  • schema expects non-array (string / number / boolean), but received string[] -> use the first value
  • schema expects array, but received string -> wrap as one-item array
  • boolean query supports true/false, 1/0, yes/no, and ?flag (treated as true)

Define body/responses params

define params by adding @body/@responses decorators to your handler

  @routeConfig({
    path: "/users/update",
    method: "put",
    tags: ["USER"],
    operationId: "UpdateUser",
  })
  @body(z.object({
    id: z.string(),
    name: z.string().optional(),
  }))
  // @body(z.any())
  // @body(z.array(z.string()))
  @responses(z.object({
    ok: z.boolean(),
  }))
  // also supported:
  // @responses(z.array(z.object({ id: z.string() })))
  // @responses(z.string())
  // @responses(z.any())

@responses currently writes the OpenAPI schema for the default success response.

Using router.prefix

const router = new SwaggerRouter({});

router.prefix("/api");

by calling router.prefix, your swagger docs routes & biz routes will automatically add prefix "/api". Open http://localhost:3000/api/swagger-html to get swagger docs.

Using Middlewares

using @middlewares decorator for your handler method

  @middlewares([
    async (ctx, next) => {
      const x = ctx._swagger_decorator_meta as ItemMeta; // get swagger decorator meta info through ctx
      console.log("biz mid", x.routeConfig);
      await next();
    },
  ])

TODO List

  • [x] support request validation
  • [ ] support response validation
  • [x] support middleware decorator
  • [x] support adding exist components to spec
  • [ ] support generate openapi docs without starting app
  • [ ] add unit test
  • [ ] support form-data request
  • [ ] support define non-200 responses
  • [ ] support class decorators