How to Add New API Documentation Endpoints in castrozan/tcc

To add new API documentation endpoints in the castrozan/tcc repository, create a TypeScript controller that extends OpenAPIRoute with a declarative schema property, implement the handle method, and register the route in server.ts using the openapi HTTP verb helpers.

The castrozan/tcc repository implements an MCP OpenAPI server built on the Hono web framework and the chanfana library. This architecture automatically generates OpenAPI specifications by introspecting TypeScript controller classes, ensuring your documentation remains synchronized with your implementation without manual YAML or JSON editing.

Architecture of the OpenAPI Generation Pipeline

The documentation generation relies on a declarative pattern centered in professionals-dummy-app/src/infrastructure/web/open-api/server.ts. Here, the system creates an openapi object via fromHono(app, …), which wraps the Hono application instance.

When you register a route using openapi.get, openapi.post, openapi.put, or openapi.delete, chanfana extracts the OpenAPIRoute subclass provided as the handler. It reads the static schema property defined on that class and merges the metadata—tags, summaries, parameters, request bodies, and response schemas—into the final OpenAPI document served at the configured docs_url (defaulting to /).

Step-by-Step Guide to Adding New API Documentation Endpoints

Step 1: Create a Controller Extending OpenAPIRoute

Create a new file in the appropriate presentation/controllers directory. The controller must extend OpenAPIRoute and define a schema object that describes the endpoint’s contract.

import { OpenAPIRoute, Bool } from 'chanfana';
import { z } from 'zod';

export class CreateEquipmentController extends OpenAPIRoute {
    schema = {
        tags: ['Equipments'],
        summary: 'Create a new equipment record',
        requestBody: {
            required: true,
            content: {
                'application/json': {
                    schema: z.object({
                        name: z.string(),
                        type: z.string(),
                        serialNumber: z.string(),
                        location: z.string().nullable()
                    })
                }
            }
        },
        responses: {
            '201': {
                description: 'Equipment created successfully',
                content: {
                    'application/json': {
                        schema: z.object({
                            success: Bool(),
                            result: z.object({
                                id: z.number(),
                                name: z.string(),
                                type: z.string(),
                                serialNumber: z.string(),
                                location: z.string().nullable(),
                                createdAt: z.string()
                            })
                        })
                    }
                }
            }
        }
    };
    
    // handle method implementation follows
}

The schema property is the single source of truth for your API documentation. chanfana uses this object to generate the corresponding OpenAPI path item when the route is registered.

Step 2: Implement the Handle Method

Add the handle method to execute business logic and return a response matching your schema definition. Use the @withErrorHandling decorator from the repository’s presentation layer for consistent error handling.

import { withErrorHandling } from 'presentation/decorators';
import { CreateEquipmentUseCase } from 'application/use-cases/equipments/CreateEquipmentUseCase';
import equipmentRepository from 'infrastructure/database/repositories/equipments';

export class CreateEquipmentController extends OpenAPIRoute {
    // schema definition from Step 1...

    @withErrorHandling
    async handle(): Promise<object> {
        const { name, type, serialNumber, location } = this.request.body as any;
        const useCase = new CreateEquipmentUseCase(equipmentRepository);
        const equipment = await useCase.execute({ name, type, serialNumber, location });

        return {
            success: true,
            result: {
                id: equipment.id,
                name: equipment.name,
                type: equipment.type,
                serialNumber: equipment.serialNumber,
                location: equipment.location,
                createdAt: equipment.createdAt.toISOString()
            }
        };
    }
}

The handle method receives the request context automatically, allowing direct access to this.request.body, this.request.params, and other Hono request properties.

Step 3: Register the Route in server.ts

Import your controller into professionals-dummy-app/src/infrastructure/web/open-api/server.ts and register it using the appropriate HTTP verb helper on the openapi instance.

import {
    CreateEquipmentController,
    // ... other existing controllers
} from 'presentation/controllers/equipments';

// ... existing Hono and openapi setup

openapi.post('/equipment', CreateEquipmentController);

This registration wires the URL path to your controller class. The fromHono utility automatically introspects the CreateEquipmentController.schema property and adds the corresponding path to the OpenAPI specification.

Step 4: Verify the Generated Documentation

Start the development server using the repository’s start script:

npm run start-tcc

Navigate to the root URL (http://localhost:<port>/) to view the generated OpenAPI UI. The new POST /equipment endpoint will appear with its request body schema, response definitions, and tag grouping exactly as declared in the controller’s schema property.

Key Files in the Documentation Pipeline

Summary

  • Extend OpenAPIRoute in a new controller file and define the schema property to declaratively specify tags, summaries, parameters, and responses.

  • Implement the handle method with business logic, optionally using the @withErrorHandling decorator for consistent error responses.

  • Register routes in professionals-dummy-app/src/infrastructure/web/open-api/server.ts using openapi.get, openapi.post, openapi.put, or openapi.delete helpers to bind URLs to controllers.

  • Documentation auto-generates at the configured docs_url (default /) when the server starts, ensuring the OpenAPI spec always reflects the current implementation.

Frequently Asked Questions

What is chanfana and why does castrozan/tcc use it?

chanfana is a TypeScript library that integrates with the Hono web framework to auto-generate OpenAPI 3.0 specifications from class-based route handlers. The castrozan/tcc repository uses it to maintain a declarative API layer where the TypeScript source code serves as the single source of truth for both implementation and documentation, eliminating the drift between code and spec files.

How does the schema property in a controller affect the final API documentation?

When you register a route using openapi.post() or similar methods, chanfana instantiates the provided OpenAPIRoute subclass and reads its static schema property. This object is merged into the master OpenAPI document object managed by fromHono(). Changes to tags, summary, requestBody, or responses in the controller immediately reflect in the generated Swagger UI at runtime without restarting the documentation server.

Can I use middleware with OpenAPIRoute controllers in this repository?

Yes. While the handle method contains the primary business logic, you can apply Hono middleware at the route registration level in server.ts (e.g., openapi.post('/equipment', authMiddleware, CreateEquipmentController)). Additionally, the repository provides the @withErrorHandling decorator to wrap the handle method in a try-catch block that standardizes error responses across all endpoints.

Where is the OpenAPI specification physically served in the castrozan/tcc project?

The specification is served at the URL configured in the fromHono() options within professionals-dummy-app/src/infrastructure/web/open-api/server.ts, defaulting to the root path /. When the MCP OpenAPI server starts, it exposes the generated JSON specification at this endpoint, which the built-in Swagger UI renders for interactive documentation.

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 →