tsoa: TypeScript OpenAPI Framework

7.0.0-alpha.0 · active · verified Sun Apr 19

tsoa is a powerful TypeScript-first framework designed to streamline the creation of REST APIs by automatically generating OpenAPI (formerly Swagger) documentation and client SDKs directly from your existing TypeScript code. It employs decorators and standard TypeScript types to define API routes, request bodies, query parameters, and response structures. A critical step involves a code generation phase that produces both the OpenAPI specification and the concrete route registration logic for popular Node.js frameworks such as Express, Hapi, and Koa. The project exhibits an active development cycle, with consistent minor releases every few months, and has recently released a v7 alpha that introduces support for OpenAPI 3.1.0 and updated Node.js version requirements. Its key differentiator is the "code-first" approach, eliminating the need to manually maintain separate OpenAPI definitions by deriving them directly from the TypeScript source, ensuring strong type consistency between API implementation and documentation. The current stable version is v6.6.0.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates setting up a basic tsoa-powered Express API, including defining a controller with decorators, registering generated routes, and serving the OpenAPI documentation using swagger-ui-express. It highlights the compile-time code generation steps necessary for tsoa applications.

// tsoa.json (in project root)
// {
//   "entryFile": "src/app.ts",
//   "controllers": ["src/controllers/**/*.ts"],
//   "spec": {
//     "outputDirectory": "build",
//     "specVersion": 3,
//     "yaml": false
//   },
//   "routes": {
//     "routesDir": "build"
//   }
// }

// src/controllers/usersController.ts
import { Controller, Route, Get, Path, Post, Body, SuccessResponse } from 'tsoa';

interface User {
  id: number;
  name: string;
}

interface CreateUserRequest {
  name: string;
}

@Route('users')
export class UsersController extends Controller {
  private users: User[] = [{ id: 1, name: 'Alice' }];

  @Get('{userId}')
  public async getUser(@Path() userId: number): Promise<User | undefined> {
    return this.users.find(u => u.id === userId);
  }

  @SuccessResponse(201, 'Created') // Set HTTP status code for success
  @Post()
  public async createUser(@Body() requestBody: CreateUserRequest): Promise<User> {
    const newUser: User = {
      id: this.users.length + 1,
      name: requestBody.name,
    };
    this.users.push(newUser);
    return newUser;
  }
}

// src/app.ts (your Express server entry file)
import express from 'express';
import { RegisterRoutes } from '../build/routes'; // Path relative to app.ts's compiled output
import * as swaggerUi from 'swagger-ui-express';
import * as path from 'path';

const app = express();
app.use(express.json()); // For parsing application/json
app.use(express.urlencoded({ extended: true })); // For parsing application/x-www-form-urlencoded

RegisterRoutes(app); // Register the tsoa-generated routes

// Serve OpenAPI UI
try {
  // Ensure 'swagger.json' is generated by `tsoa spec` in your build directory
  const swaggerDocument = require(path.resolve(__dirname, '../build/swagger.json'));
  app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
} catch (error) {
  console.error('Failed to load swagger.json. Did you run `tsoa spec`?', error);
}

// Generic error handler middleware
app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
  console.error(err);
  const status = err.status || 500;
  const message = err.message || 'An unexpected error occurred.';
  res.status(status).json({ message });
});

const port = process.env.PORT || 3000;
app.listen(port, () => {
  console.log(`Server running on http://localhost:${port}`);
  console.log(`API docs available at http://localhost:${port}/docs`);
});

// To run this application:
// 1. Install dependencies: `npm install express tsoa swagger-ui-express @types/express @types/swagger-ui-express typescript ts-node @tsoa/runtime`
// 2. Configure `tsconfig.json` with: `"experimentalDecorators": true`, `"emitDecoratorMetadata": true` (recommended).
// 3. Add scripts to `package.json`: `"tsoa:gen": "tsoa spec && tsoa routes", "build": "npm run tsoa:gen && tsc", "start": "npm run build && node build/app.js"`
// 4. Run `npm start` to build and launch the server.

view raw JSON →