How OpenAPI Documentation is Auto-Generated from Decorators in the TCC Repository

The TCC repository uses the chanfana library to automatically generate OpenAPI documentation by extending the OpenAPIRoute base class in controllers and registering them with fromHono, eliminating the need for manual YAML or JSON specification files.

The castrozan/tcc repository demonstrates a modern approach to API development where documentation stays synchronized with implementation code. By leveraging chanfana—a thin wrapper around the Hono web framework—the project auto-generates complete Swagger UI documentation directly from TypeScript decorators and static schema definitions.

The Architecture Behind Auto-Generated OpenAPI Documentation

The chanfana Library and OpenAPIRoute Base Class

At the heart of the system is the OpenAPIRoute class provided by chanfana. Controllers in the TCC repository extend this base class to gain OpenAPI generation capabilities. Each controller defines a static schema property that follows the OpenAPI v3 specification structure, including tags, request bodies, responses, and security requirements.

When a controller extends OpenAPIRoute, chanfana can introspect the class at runtime to extract the declarative schema and map it to the corresponding HTTP endpoint.

The fromHono Factory Function

The fromHono function initializes the integration between Hono and chanfana. It accepts a Hono application instance and configuration options, returning an enhanced object that manages both route registration and OpenAPI documentation assembly.

This factory creates an internal registry that accumulates path definitions, security schemes, and component schemas as controllers are registered.

Step-by-Step Implementation Flow

1. Define Controllers Extending OpenAPIRoute

Each API endpoint is implemented as a class that extends OpenAPIRoute and provides a static schema object. For example, in src/presentation/controllers/professionals/CreateProfessionalController.ts:

import { Bool, OpenAPIRoute } from 'chanfana';
import { CreateProfessionalUseCase } from 'application/use-cases/professionals/CreateProfessionalUseCase';
import { withErrorHandling } from 'presentation/decorators';
import { z } from 'zod';

export class CreateProfessionalController extends OpenAPIRoute {
  schema = {
    tags: ['Professionals'],
    summary: 'Create a new professional',
    security: [{ bearerAuth: [] }],
    request: {
      body: {
        content: {
          'application/json': {
            schema: z.object({
              name: z.string().min(1),
              role: z.string().min(1),
            })
          }
        }
      }
    },
    responses: {
      '201': {
        description: 'Created',
        content: {
          'application/json': {
            schema: z.object({
              success: Bool(),
              result: z.object({ id: z.number() })
            })
          }
        }
      }
    }
  };

  @withErrorHandling
  async handle() {
    // Implementation logic
  }
}

The schema property uses Zod for runtime validation and OpenAPI schema generation, while OpenAPIRoute enables chanfana to discover this metadata.

2. Register Routes with fromHono

In src/infrastructure/web/open-api/server.ts, the server bootstrap registers controllers using methods on the object returned by fromHono:

import { fromHono } from 'chanfana';
import { Hono } from 'hono';
import { config } from 'dotenv';
import {
  CreateProfessionalController,
  DeleteProfessionalController,
  FindAllProfessionalController,
  FindByIdProfessionalController,
  UpdateProfessionalController
} from 'presentation/controllers/professionals';

const app = new Hono();

const openapi = fromHono(app, {
  docs_url: '/',
  schema: {
    security: [{ bearerAuth: [] }]
  }
});

openapi.registry.registerComponent('securitySchemes', 'bearerAuth', {
  type: 'http',
  scheme: 'bearer'
});

config();

openapi.get('/public/professional', FindAllProfessionalController);
openapi.get('/public/professional/:id', FindByIdProfessionalController);
openapi.put('/professional', UpdateProfessionalController);
openapi.post('/professional', CreateProfessionalController);
openapi.delete('/professional/:id', DeleteProfessionalController);

export default app;

Each openapi.<method>() call extracts the static schema from the controller and adds it to the internal OpenAPI registry.

3. Configure Security Components

The server registers a reusable bearerAuth security scheme using openapi.registry.registerComponent. This scheme is referenced in each controller's security array, ensuring consistent authentication documentation across all endpoints.

4. Serve Documentation via docs_url

The docs_url: '/' configuration option instructs fromHono to expose Swagger UI at the root path. When the server starts, chanfana assembles the complete OpenAPI specification from the registry and serves it at this endpoint.

How the OpenAPI JSON Specification is Produced

During server initialization, fromHono constructs an internal OpenAPIV3.Document object. For each registered route, the library:

  1. Reads the HTTP method from the registration call (get, post, put, delete).
  2. Introspects the controller class to extract the static schema property.
  3. Maps the schema to the corresponding paths[<path>][<method>] entry in the OpenAPI document.
  4. Merges globally registered components, such as the bearerAuth security scheme.

When a client requests the docs_url endpoint, chanfana returns the fully populated specification, which Swagger UI renders into interactive documentation.

Summary

  • The chanfana library enables OpenAPI documentation auto-generated from decorators by providing the OpenAPIRoute base class.
  • Controllers define declarative schema objects that follow OpenAPI v3 structure, using Zod for type safety and validation.
  • The fromHono factory function registers routes and automatically assembles the OpenAPI specification into an internal registry.
  • Security components like bearerAuth are registered once and referenced across all controllers for consistent authentication documentation.
  • The docs_url configuration serves Swagger UI automatically, ensuring documentation stays synchronized with code changes without manual maintenance.

Frequently Asked Questions

What library does the TCC repository use for OpenAPI auto-generation?

The repository uses chanfana, a thin wrapper around the Hono web framework. Chanfana provides the OpenAPIRoute base class and fromHono factory function that enable automatic OpenAPI specification generation from TypeScript controller classes and their static schema definitions.

How does the schema property in controllers relate to OpenAPI specification?

The schema property is a static object defined on each controller class that extends OpenAPIRoute. It follows the OpenAPI v3 specification structure, including properties like tags, summary, request, responses, and security. Chanfana reads this static property during route registration and maps it directly to the corresponding path and method in the generated OpenAPI document.

Is manual YAML or JSON required to maintain API documentation in this setup?

No manual YAML or JSON files are required. The documentation is generated entirely from the TypeScript source code. Developers only need to maintain the schema property within their controller classes. When the server starts, fromHono assembles the complete OpenAPI specification from these schemas, and the docs_url endpoint serves the Swagger UI automatically.

What role does the fromHono function play in documentation generation?

The fromHono function initializes the integration between the Hono application and chanfana's OpenAPI registry. It returns an enhanced object that provides methods like get, post, put, and delete for registering routes. When these methods are called with a controller class, fromHono introspects the class to extract its schema, registers the route with Hono, and adds the corresponding OpenAPI path entry to an internal registry that ultimately produces the complete specification document.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →