Docus Logo
Charcole Swagger

Introduction to Charcole Swagger Documentation

Learn how @charcoles/swagger eliminates schema duplication and makes API documentation effortless.

What is @charcoles/swagger?

If you've worked on any serious backend project, you know the pain of API documentation.

You write a Zod schema for validation. Then you write the exact same thing again in Swagger YAML. Then when requirements change, you update both places. Then they drift. Then Swagger lies. Then nobody trusts the docs anymore.

This is not a small problem. It is exhausting, repetitive, and completely unnecessary.

@charcoles/swagger exists to end this cycle.

It automatically converts your Zod validation schemas into OpenAPI documentation. You define schemas once. Documentation generates itself. Always accurate. Always in sync. No duplication.


Why @charcoles/swagger exists

The fundamental problem with API documentation is that schemas are written twice.

Once in code for validation. Once in YAML for documentation.

Both describe the same thing. Both need to stay synchronized. Both are maintained manually.

This approach breaks down immediately in real projects.

When a field changes from optional to required, developers update the Zod schema but forget the Swagger comment. When validation rules get stricter, the documentation stays outdated. When deadlines approach, documentation gets skipped entirely.

The real issue is not laziness. The issue is that duplication is fundamentally unsafe.

@charcoles/swagger removes the duplication entirely. Schemas are defined once in Zod. Documentation is generated automatically from that single source of truth.

This is not just convenient. It is structurally impossible for documentation to drift.


What @charcoles/swagger actually does

The workflow is simple.

You define your validation schemas in Zod like you already do:

export const createUserSchema = z.object({
  body: z.object({
    name: z.string().min(1).max(100),
    email: z.string().email(),
    password: z.string().min(8),
  }),
});

Then you register them once in your Swagger config:

setupSwagger(app, {
  schemas: {
    createUserSchema, // Auto-converted to OpenAPI
  },
});

Now in your route documentation, instead of writing 50+ lines of manual YAML, you write one line:

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

That's it.

Change your Zod schema tomorrow? Documentation updates automatically. Add a new field? It appears in Swagger immediately. Tighten validation rules? Docs reflect it instantly.

Single source of truth. Zero duplication. Always accurate.


The scale of the problem @charcoles/swagger solves

Before @charcoles/swagger, a typical authenticated endpoint required around 76 lines of Swagger documentation.

6 lines for the Zod schema. 70 lines for the manual OpenAPI duplication.

Every single endpoint.

In a project with 20 endpoints, that's 1,400 lines of pure duplication. Copy-paste errors everywhere. Outdated descriptions. Wrong examples. Validation and documentation constantly out of sync.

With @charcoles/swagger, those same 20 endpoints require 400 lines total.

That's a 74% reduction in documentation overhead, and more importantly, zero possibility of drift.

This is not a marginal improvement. This is elimination of an entire class of problems.


Built-in response templates

One of the most annoying parts of Swagger documentation is writing the same response schemas over and over.

Every endpoint returns success. Every POST returns validation errors. Every protected route can return unauthorized.

Copy-pasting these response definitions is mind-numbing and error-prone.

@charcoles/swagger includes six common response templates that work out of the box:

  • Success (200/201)
  • ValidationError (400)
  • Unauthorized (401)
  • Forbidden (403)
  • NotFound (404)
  • InternalError (500)

Instead of writing 20 lines of YAML for each response, you write one:

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

Same response. Standard format. No duplication. No maintenance.

These templates handle 90% of common API responses. For the remaining 10%, you can define custom responses once and reuse them the same way.


Why this matters for real projects

In early-stage projects, documentation often gets skipped because deadlines matter more than docs.

In mid-stage projects, documentation exists but is partially outdated because nobody has time to maintain two versions of the same schema.

In mature projects, documentation is carefully maintained through processes, reviews, and discipline — but all that effort is just fighting the duplication problem.

@charcoles/swagger removes the tradeoff entirely.

Documentation is not extra work. It is automatic. There is no maintenance burden because there is only one schema. Accuracy is guaranteed because generation happens at runtime from the actual validation rules.

This means small teams can have excellent documentation without slowing down, and large teams can eliminate an entire category of bugs without adding process overhead.


Separation that actually works

@charcoles/swagger does not lock you into anything.

It works with any Express.js project. You can install it via npm install @charcoles/swagger and use it even if you never used Charcole itself.

It does not force you to change your validation approach. It does not force you to change your response format. It does not force you to use TypeScript.

It simply takes your existing Zod schemas and converts them to OpenAPI format.

If you later want to switch to a different documentation approach, you can. The schemas are standard Zod. The Swagger output is standard OpenAPI 3.0. Nothing proprietary. Nothing locked in.

This is architectural simplicity: solve one problem extremely well, stay out of the way everywhere else.


The long-term advantage

The real benefit of @charcoles/swagger is not immediate.

It is what happens six months later when a new team member joins and sees documentation that is actually correct.

It is what happens when a critical field changes and the API, validation, and documentation all update together because they share the same source.

It is what happens when your API grows to 100 endpoints and you realize documentation never became a bottleneck because it was never duplicated in the first place.

Good architecture is not impressive. It is invisible. It quietly prevents problems that never get a chance to exist.

@charcoles/swagger does exactly that.


Final thoughts

@charcoles/swagger is not fancy. It does not have AI features. It does not integrate with 47 clouds.

It solves one specific problem: schema duplication in API documentation.

It does this by treating your Zod schemas as the single source of truth and generating OpenAPI specs automatically.

The result is less code, better accuracy, and documentation that actually stays correct.

If you write APIs with Express and Zod, this is one of the simplest and highest-impact improvements you can make.