# How to Add New API Documentation Endpoints in castrozan/tcc

> Learn to add new API documentation endpoints in castrozan/tcc. Create TypeScript controllers, implement the handle method, and register routes easily.

- Repository: [Lucas Zanoni⠀⠀⠀⠀⠀ ⠀╱|、 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ (˚ˎ 。7 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ |、˜〵 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ じしˍ,)ノ/tcc](https://github.com/castrozan/tcc)
- Tags: how-to-guide
- Published: 2026-02-27

---

**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`](https://github.com/castrozan/tcc/blob/main/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`](https://github.com/castrozan/tcc/blob/main/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.

```typescript
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.

```typescript
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`](https://github.com/castrozan/tcc/blob/main/professionals-dummy-app/src/infrastructure/web/open-api/server.ts) and register it using the appropriate HTTP verb helper on the `openapi` instance.

```typescript
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:

```bash
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

- **[`professionals-dummy-app/src/infrastructure/web/open-api/server.ts`](https://github.com/castrozan/tcc/blob/main/professionals-dummy-app/src/infrastructure/web/open-api/server.ts)** – Bootstraps the Hono application, initializes the `openapi` helper via `fromHono(app, …)`, configures security schemes, and maps URL paths to controller implementations.

- **[`professionals-dummy-app/src/presentation/controllers/professionals/FindAllProfessionalController.ts`](https://github.com/castrozan/tcc/blob/main/professionals-dummy-app/src/presentation/controllers/professionals/FindAllProfessionalController.ts)** – Serves as the canonical reference for controller structure, demonstrating the `schema` definition pattern and `handle` method implementation used throughout the codebase.

- **[`mcp-openapi-server/src/openapi-loader.ts`](https://github.com/castrozan/tcc/blob/main/mcp-openapi-server/src/openapi-loader.ts)** – Internal utility that loads and validates the generated OpenAPI JSON specification when the MCP server initializes.

- **[`mcp-openapi-server/src/config.ts`](https://github.com/castrozan/tcc/blob/main/mcp-openapi-server/src/config.ts)** – Defines runtime configuration options including the `--openapi-spec` source path and server metadata.

## 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`](https://github.com/castrozan/tcc/blob/main/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`](https://github.com/castrozan/tcc/blob/main/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`](https://github.com/castrozan/tcc/blob/main/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.