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

@charcoles/swagger

v1.0.0

Published

Auto-generated Swagger documentation for Charcole APIs

Downloads

32

Readme

@charcoles/swagger

Effortless API documentation for Express.js applications. Automatically generates OpenAPI 3.0 specs from your Zod validation schemas.

Features

Zero Schema Duplication - Define schemas once in Zod, use everywhere 🚀 60-80% Less Code - Minimal documentation overhead 🔄 Always In Sync - Impossible to have outdated docs 📦 Built-in Templates - Common response schemas included 🎯 Framework Agnostic - Works with any Express.js project 💪 TypeScript First - Full type safety with optional JavaScript support

Installation

npm install @charcoles/swagger zod

Quick Start

1. Setup Swagger in your Express app

import express from "express";
import { setupSwagger } from "@charcoles/swagger";
import { createUserSchema, loginSchema } from "./schemas";

const app = express();

setupSwagger(app, {
  title: "My API",
  version: "1.0.0",
  schemas: {
    createUserSchema, // Auto-converted from Zod!
    loginSchema,
  },
});

app.listen(3000);
// Swagger UI now available at http://localhost:3000/api-docs

2. Document your endpoints

Traditional Way (Manual Schema - 76 lines):

/**
 * @swagger
 * /api/users:
 *   post:
 *     requestBody:
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required:
 *               - name
 *               - email
 *             properties:
 *               name:
 *                 type: string
 *                 minLength: 1
 *                 maxLength: 100
 *               email:
 *                 type: string
 *                 format: email
 *               ... 50+ more lines
 */
router.post("/users", createUser);

With @charcoles/swagger (16 lines):

/**
 * @swagger
 * /api/users:
 *   post:
 *     summary: Create a new user
 *     tags:
 *       - Users
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             $ref: '#/components/schemas/createUserSchema'
 *     responses:
 *       201:
 *         $ref: '#/components/responses/Success'
 *       400:
 *         $ref: '#/components/responses/ValidationError'
 */
router.post("/users", createUser);

API Reference

setupSwagger(app, options)

Sets up Swagger UI and documentation generation.

Options

| Option | Type | Default | Description | | ------------------------ | ------- | ---------------------------------- | ----------------------------------- | | title | string | "Charcole API" | API title | | version | string | "1.0.0" | API version | | description | string | "Auto-generated API documentation" | API description | | path | string | "/api-docs" | Swagger UI path | | servers | array | [{url: "http://localhost:3000"}] | Server URLs | | schemas | object | {} | Zod schemas to auto-register | | includeCommonResponses | boolean | true | Include built-in response templates | | customResponses | object | {} | Additional custom response schemas |

Example

setupSwagger(app, {
  title: "My E-commerce API",
  version: "2.0.0",
  description: "Production-ready REST API for e-commerce",
  path: "/docs",
  servers: [
    { url: "https://api.example.com", description: "Production" },
    { url: "http://localhost:3000", description: "Development" },
  ],
  schemas: {
    createProductSchema,
    updateProductSchema,
    orderSchema,
  },
  customResponses: {
    ProductCreated: {
      description: "Product created successfully",
      content: {
        "application/json": {
          schema: {
            type: "object",
            properties: {
              productId: { type: "string" },
              name: { type: "string" },
            },
          },
        },
      },
    },
  },
});

Built-in Response Templates

The following responses are automatically available:

  • Success (200/201) - Standard success response
  • ValidationError (400) - Request validation failures
  • Unauthorized (401) - Authentication failures
  • Forbidden (403) - Permission denied
  • NotFound (404) - Resource not found
  • InternalError (500) - Server errors

Use them with $ref:

responses:
  200:
    $ref: "#/components/responses/Success"
  400:
    $ref: "#/components/responses/ValidationError"

Helper Functions

convertZodToOpenAPI(zodSchema, name)

Converts a Zod schema to OpenAPI 3.0 JSON Schema.

import { convertZodToOpenAPI } from "@charcoles/swagger";
import { z } from "zod";

const userSchema = z.object({
  name: z.string(),
  email: z.string().email(),
});

const openApiSchema = convertZodToOpenAPI(userSchema, "User");

registerSchemas(schemas)

Registers multiple Zod schemas at once.

import { registerSchemas } from "@charcoles/swagger";

const components = registerSchemas({
  createUserSchema,
  updateUserSchema,
  loginSchema,
});

getCommonResponses()

Returns all built-in response templates.

import { getCommonResponses } from "@charcoles/swagger";

const responses = getCommonResponses();
// { Success: {...}, ValidationError: {...}, Unauthorized: {...}, ... }

Integration with Zod

@charcoles/swagger seamlessly integrates with your Zod validation schemas:

// Define schema once
export const createUserSchema = z.object({
  body: z.object({
    name: z.string().min(1, "Name is required").max(100),
    email: z.string().email("Invalid email"),
    password: z.string().min(8, "Password must be at least 8 characters"),
  }),
});

// Register in swagger config
setupSwagger(app, {
  schemas: { createUserSchema },
});

// Use in controller with validation
const createUser = async (req, res) => {
  const { body } = createUserSchema.parse({ body: req.body });
  // Your logic here
};

// Reference in documentation
/**
 * @swagger
 * /api/users:
 *   post:
 *     requestBody:
 *       content:
 *         application/json:
 *           schema:
 *             $ref: '#/components/schemas/createUserSchema'
 */

Single source of truth! Change your Zod schema, and both validation and documentation update automatically.

TypeScript Support

Full TypeScript support with type definitions included:

import { setupSwagger, SwaggerOptions, OpenAPISpec } from "@charcoles/swagger";
import type { Application } from "express";

const app: Application = express();

const options: SwaggerOptions = {
  title: "My API",
  version: "1.0.0",
  schemas: {
    mySchema,
  },
};

const spec: OpenAPISpec = setupSwagger(app, options);

JavaScript Support

Works perfectly with JavaScript projects too:

const express = require("express");
const { setupSwagger } = require("@charcoles/swagger");
const { z } = require("zod");

const app = express();

const userSchema = z.object({
  name: z.string(),
  email: z.string().email(),
});

setupSwagger(app, {
  title: "My JavaScript API",
  schemas: { userSchema },
});

Examples

Complete CRUD API

import { z } from "zod";
import { setupSwagger } from "@charcoles/swagger";

// Define schemas
const createPostSchema = z.object({
  body: z.object({
    title: z.string().min(1).max(200),
    content: z.string().min(1),
    published: z.boolean().default(false),
  }),
});

const updatePostSchema = z.object({
  body: z.object({
    title: z.string().min(1).max(200).optional(),
    content: z.string().min(1).optional(),
    published: z.boolean().optional(),
  }),
});

// Setup Swagger
setupSwagger(app, {
  title: "Blog API",
  schemas: {
    createPostSchema,
    updatePostSchema,
  },
});

// Document routes
/**
 * @swagger
 * /api/posts:
 *   get:
 *     summary: Get all posts
 *     tags: [Posts]
 *     responses:
 *       200:
 *         $ref: '#/components/responses/Success'
 *
 *   post:
 *     summary: Create a new post
 *     tags: [Posts]
 *     security:
 *       - bearerAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             $ref: '#/components/schemas/createPostSchema'
 *     responses:
 *       201:
 *         $ref: '#/components/responses/Success'
 *       400:
 *         $ref: '#/components/responses/ValidationError'
 *       401:
 *         $ref: '#/components/responses/Unauthorized'
 *
 * /api/posts/{id}:
 *   get:
 *     summary: Get post by ID
 *     tags: [Posts]
 *     parameters:
 *       - in: path
 *         name: id
 *         required: true
 *         schema:
 *           type: string
 *     responses:
 *       200:
 *         $ref: '#/components/responses/Success'
 *       404:
 *         $ref: '#/components/responses/NotFound'
 *
 *   put:
 *     summary: Update post
 *     tags: [Posts]
 *     security:
 *       - bearerAuth: []
 *     parameters:
 *       - in: path
 *         name: id
 *         required: true
 *         schema:
 *           type: string
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             $ref: '#/components/schemas/updatePostSchema'
 *     responses:
 *       200:
 *         $ref: '#/components/responses/Success'
 *       400:
 *         $ref: '#/components/responses/ValidationError'
 *       401:
 *         $ref: '#/components/responses/Unauthorized'
 *       404:
 *         $ref: '#/components/responses/NotFound'
 *
 *   delete:
 *     summary: Delete post
 *     tags: [Posts]
 *     security:
 *       - bearerAuth: []
 *     parameters:
 *       - in: path
 *         name: id
 *         required: true
 *         schema:
 *           type: string
 *     responses:
 *       204:
 *         description: Post deleted successfully
 *       401:
 *         $ref: '#/components/responses/Unauthorized'
 *       404:
 *         $ref: '#/components/responses/NotFound'
 */

Benefits

Before @charcoles/swagger

// Zod schema (for validation)
const createUserSchema = z.object({
  body: z.object({
    name: z.string().min(1).max(100),
    email: z.string().email(),
  }),
});

// Swagger docs (manual duplication - 45 lines)
/**
 * @swagger
 * /api/users:
 *   post:
 *     requestBody:
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required: [name, email]
 *             properties:
 *               name:
 *                 type: string
 *                 minLength: 1
 *                 maxLength: 100
 *               email:
 *                 type: string
 *                 format: email
 *     responses:
 *       201:
 *         description: User created
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 success:
 *                   type: boolean
 *                 ... 20+ more lines
 */

Problems:

  • ❌ Schema defined twice
  • ❌ 45+ lines of docs per endpoint
  • ❌ Easy to get out of sync
  • ❌ Copy-paste errors
  • ❌ High maintenance burden

After @charcoles/swagger

// Zod schema (single source of truth)
const createUserSchema = z.object({
  body: z.object({
    name: z.string().min(1).max(100),
    email: z.string().email(),
  }),
});

// Register once
setupSwagger(app, {
  schemas: { createUserSchema },
});

// Reference in docs (15 lines)
/**
 * @swagger
 * /api/users:
 *   post:
 *     summary: Create user
 *     tags: [Users]
 *     requestBody:
 *       content:
 *         application/json:
 *           schema:
 *             $ref: '#/components/schemas/createUserSchema'
 *     responses:
 *       201:
 *         $ref: '#/components/responses/Success'
 *       400:
 *         $ref: '#/components/responses/ValidationError'
 */

Benefits:

  • ✅ Schema defined once
  • ✅ 15 lines of docs (70% reduction)
  • ✅ Always in sync (impossible to drift)
  • ✅ No duplication
  • ✅ Easy to maintain

Comparison

| Feature | @charcoles/swagger | swagger-jsdoc | tsoa | NestJS | | ----------------------- | ------------------ | ------------- | ------ | ------ | | Zero duplication | ✅ | ❌ | ✅ | ✅ | | Framework agnostic | ✅ | ✅ | ❌ | ❌ | | JavaScript support | ✅ | ✅ | ❌ | ❌ | | Auto Zod conversion | ✅ | ❌ | ❌ | ⚠️ | | No build step | ✅ | ✅ | ❌ | ✅ | | Lines of code | Very Low | High | Low | Medium | | Learning curve | Easy | Easy | Medium | High |

Troubleshooting

Schema not appearing in Swagger UI?

  1. Verify the schema is imported in your config
  2. Restart your server
  3. Check console for errors during startup

Zod schema not converting correctly?

  • Use standard Zod primitives when possible
  • Avoid complex .transform() or .refine() for documented schemas
  • Check that zod-to-json-schema supports your Zod features

Want more control?

Use the helper functions for custom conversions:

import { convertZodToOpenAPI } from "@charcoles/swagger";

const customSchema = convertZodToOpenAPI(myZodSchema, "MySchema");
// Modify customSchema as needed

License

ISC

Author

Sheraz Manzoor

Contributing

Issues and PRs welcome at https://github.com/your-repo/charcole


@charcoles/swagger - Because life's too short to write schemas twice. 🎉