Skip to main content
  1. Today I Learned/

Why I chose 'routing-controllers' over 'tsoa' for building routing and documenting APIs.

·626 words·3 mins
This article is part of the TIL series. 📝
and you can check details code on here

Summary #

Creating type-safe routing and documenting is vital when building a Restful API server. In Express.js with TypeScript, some popular options for defining the routes are routing-controllers, tsoa and Nest.js.
But I will exclude Nest.js in this article because we need to apply it to an application already configured with native express.js.
So this article will explain the difference between the other two options and why I chose routing-controllers over tsoa.


Details #

Comparison #

routing-controllerstsoa
Type-Safe RoutingDecorator-basedCode-generation and using decorators
FlexibilityDecorator-based, with a variety of decorators for fine-grained controlCode-generation, with limited customization options
DocumentationAutomatically generates OpenAPI (Swagger) schema object.Automatically generates OpenAPI (Swagger) JSON file.
Supports customizing the generated documentation.
Type-Safe Routing
  • routing-controllers
    It is decorator-based, meaning you can use decorators to define your routes and controllers. It also provides a simpler and more intuitive approach to routing by allowing you to define your routes and controllers in a way that is easy to read and understand.

  • tsoa
    It is code-generation and uses decorators. It takes your TypeScript code, looks for decorators, generates the necessary express routes, and the OpenAPI specification for your API. It aims to provide a more automated and less error-prone approach to API development by using TypeScript decorators to describe your API.

  • both of them are type-safe.
    using class-validator, you can validate the request body, params, query, and headers.

Flexibility
  • routing-controllers
    It is decorator-based, with a variety of decorators for fine-grained control. It provides a lot of decorators for customization. It also supports a wide range of middleware and libraries.

  • tsoa
    It is code-generation with limited customization options. It generates boilerplate code, saving time and effort. But it can be less flexible and require additional setups such as a tsoa config file for building a routing file & an open API JSON file.

  • routing-controllers is more flexible than tsoa.
    It can use its existing middleware. Also, unlike tsoa, you can use express.req and express.res inside the controller.

Documentation
  • routing-controllers
    It automatically generates OpenAPI (Swagger) schema object.
    Generates OpenAPI (Swagger) specs automatically without any handling option. But it needs to use third-party libraries, such as routing-controllers-openapi and class-validator-jsonschema.

  • tsoa
    It automatically generates OpenAPI (Swagger) JSON file.
    Supports customizing the generated documentation. It generates OpenAPI (Swagger) specs automatically. But it can be less flexible and require additional setups such as a tsoa config file for building a routing file & an open API JSON file below.

    example tsoa config file and script in package.json - package.json
    1
    2
    3
    4
    5
    6
    7
    8
    
    {
      ...
      "scripts": {
        "build": "tsoa spec-and-routes -c=tsoa.production.json  && tsc -p ./",
        "dev": "cross-env NODE_ENV=development concurrently \"nodemon -x tsoa spec-and-routes -c=tsoa.json\" \"nodemon\"",
      }
      ...
    }
    - tsoa.json, tsoa.production.json
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    {
      "entryFile": "src/server.ts",
      "noImplicitAdditionalProperties": "throw-on-extras",
      "controllerPathGlobs": ["src/**/*.controller.ts"],
      "spec": {
        "host": "localhost:3000",
        "basePath": "/api",
        "schemes": ["http"],
        "outputDirectory": "src",
        "specVersion": 3
      },
      "routes": {
        "routesDir": "src",
        "basePath": "/api"
      },
      "compilerOptions": {
        "baseUrl": "src",
        "paths": {
          "@/*": ["*"]
        },
        "ignoreFiles": ["src/**/*.test.ts", "src/**/*.test.tsx", "src/**/*.test.js", "src/**/*.test.jsx"]
      }
    }
  • tsoa is more convenient, but routing-controllers is more flexible.


Conclusion #

I tried both methods to add type-safe routing and documentation to an already implemented express server, and My choice was routing-controllers.

tsoa had a lot of modifications to make to use the library, so it was inconvenient. to generate the spec and route codes, i also needed to modify the server execution script in package.json.

routing-controller was a much better option to me, allowing us to use the already implemented middleware and controller logic and write more detailed swagger documentation.