Creando una API con TSOA

07 agosto 2019

TSOA, creando una API de forma 'ágil'

TSOA es una librería que trae muchas ventajas a la hora de crear una API de cualquier tipo, librando así al programador la tarea de crear mucho código que se repite para ir al meollo a la hora de crear nuevas rutas.
A parte genera una documentación, en caso de que queramos, basada en el estándar swagger, lo que abre una gran puerta a la hora de documentar la API.

TSOA nos permite crear con una estructura muy clara la API, esto lo hacemos extendiendo de su clase 'Controller' para añadir nuestras rutas, he estado en proyectos que con solo este pensamiento se hubiese ahorrado bastante tiempo.

Creando el proyecto

El proyecto es uno cualquiera de TypeScript al que vamos a añadir estas dependencias:

npm install express swagger-ui-express tsoa typescript

Y los types como dependencias de desarrollo

npm install --save-dev @types/node @types/express

Y un archivo index.ts para empezar, a mi me queda de esta forma:

  • src
    • index.ts
  • package.json

Montando el index.ts

Fichero inicial de la aplicación, en este aprovecho para llamara a varios procedimientos siempre pero que hoy no voy a listar porque no servirá de nada.

Me llama más la atención crear una clase y que contenga todo los métodos

import * as bodyParser from "body-parser";

import * as express from "express";

import * as swaggerUi from "swagger-ui-express";

import { RegisterRoutes } from "./routes";

import { Logger } from "./utils/logger";

// Archivo que carga los controladores, más adelante toca

import  "./core/controllers/index";

class Server {

    private Port: number;

    private App: express.Express;

    constructor() {

        this.createApp();

        this.config();

        this.launchSwagger();

        this.startUp();

    }

    // Levantamos la aplicación de express y le decimos que cabeceras

    // va a aceptar, las que no entren aquí no pasarán.

    private createApp() {

        this.Port = +process.env.PORT || 8080;

        this.App = express();

        this.App.use(

            (req, res, next) => {

                res.header("Access-Control-Allow-Origin", "*");

                res.header("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");

                res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");

                next();

            }

        );

        // Esto es un console log pero con clase propia y colorines, nada más

        Logger.log("createApp acabado");

    }

    // Se podría poner en el createApp() pero lo añado aquí, de digo que

    // acepte urlencoded (body con formularios y tal) y que será json.

    private config() {

        this.App.use(bodyParser.urlencoded({ extended: true }));

        this.App.use(bodyParser.json());

        Logger.log("config acabado");

    }

    // Importante, aquí cargo el swagger.json y configuro su ruta, ahora

    // comento de que va esto ya que es un punto clave.

    private launchSwagger() {

        try {

            const swaggerDocument = require("./swagger.json");

            this.App.use("/swagger", swaggerUi.serve, swaggerUi.setup(swaggerDocument));

        } catch (err) {

            Logger.log("index.ts: no se ha podido cargar el archivo swagger.json");

        }

        Logger.log("launchSwagger acabado");

    }
    
    new Server();

Aquí está el ejemplo de como pienso que hace este proceso para arrancar el servidor, ojo, aún no funciona pues nos falta crear un par de archivos más y apañar el package.json con los comandos apropiados.

Creando los controladores

Estos archivos son los que contienen nuestras rutas (endpoints, rest api, etc.) dentro de estos declaramos la lógica que hará el servidor al recibir una petición. Yo los creo en esta ruta:

  • src
    • core
      • controllers
        • index.ts
        • user.controller.ts
    • index.ts
  • package.json
// index.ts
export * from "./user.controller";

El único objetivo de este archivo es el de reunir todos los controladores y así cargarlos de golpe en el arranque del servidor, cada vez que añadamos un nuevo controlador tiene que estar aquí.