Blog

Plugcore framework, gestión de APIs

Introducción a Plugcore

¡Hola!

Hoy os queremos presentar Plugcore un framework que hemos estado preparando desde hace un tiempo para crear nuestras propias APIs para nuestros clientes. Está creado desde 0 en Typescript y nos hemos ayudado de algunas librerías en puntos clave, sobretodo Fastify en la parte web.

La idea de este framework es guiar al programador en todos los pasos que requiere la implementación de una API con todas las características que necesita hoy en día, empezando desde 0, es decir desde no tener más que una carpeta vacía hasta tener un servidor funcionando.

En la parte de persistencia del framework, de momento sólo tenemos soporte para MongoDB, pero iremos sacando nuevos conectores según se vea necesario. De todas maneras es muy sencillo implementar un conector del sistema de persistencia preferido, ya que en este framework tenemos la filosofía de no usar ORMs ni cosas parecidas, puesto que al final aprendes sólo ese ORM y siempre hay necesidades de casos que no lo contempla y siempre son más problemas (esto da para una conversación mucho más larga, pero es para tener una idea).

Antes de empezar a crear nuestro proyecto, es necesario entender cómo está estructurado el framework, actualmente tenemos estos 3 módulos:

  • @plugcore/core: Este es el módulo principal y el que es la base de cualquier proyecto hecho en Plugcore. Tiene todos los elementos que sean genéricos como por ejemplo el inyector de dependencias, pero además también tiene otras utilidades como el sistema de logs, configuración del proyecto, validador de objetos y un framework de tests.
  • @plugcore/web: Aquí está todo lo relacionado con la publicación de API, desde gestionar las rutas, documentarlas, eventos, validaciones, etc.
  • @plugcore/ds-mongodb Este es nuestro primer datasource de base de datos, en este caso MongoDB, y lo que nos permite es conectarnos a una o más instancias de MongoDb de forma sencilla usando el sistema de configuración e inyección de dependencias de Plugcore.

Los proyectos hechos con este framework necesitan tener una estructura concreta para iniciarse, en futuros blogs veremos y entenderemos mejor cómo se ejecuta el framework pero de momento está todo documentado en la wiki del proyecto.

Es por ello que hemos creado un pequeño cli para ayudarnos con la instalación inicial.

Para este ejemplo vamos a crear una pequeña API que va a usar una MongoDb para persistir los datos, pero para hacerlo más sencillo vamos a "engañar" al sistema usando una base de datos en memoria para no tener que preocuparnos de hacer una instalación de mongo por el momento, no nos servirá para persistir los datos pero sí que para hacer una pequeña demo o ejecutar tests.

Antes de empezar debemos tener:

  • NodeJS y npm instalado, a poder ser la versión 12 o superior.
  • Acceso a una consola/terminal, por ejemplo en windows PowerShell, o en Mac/Linux, la que venga de base.

Bueno, sin más preámbulo, vamos a empezar con la instalación, y para ello necesitamos primero una carpeta con el nombre del proyecto que queremos, normalmente habremos creado un repositorio GIT en algún servidor y lo habremos clonado, pero de momento la demo podemos ejecutar desde la terminal:

mkdir myproject
cd myproject
npx @plugcore/core init

Nos van a aparecer algunas preguntas, para nuestro ejemplo vamos a contestar Y (Yes) a todas ellas:

Do you want to create a basic demo with the "web" and "ds-mongodb" modules? (Y/n): Y
Do you want to use an in memory database mocked as MongoDB for development or tests purposes? (Y/n): Y

Una vez la instalación a terminado, nos quedará una estructura del proyecto parecida a esta:

myproject/-- Carpeta del proyecto
├── configuration/-- Carpeta encargada de guardar todos los archivos de configuración
     ├── configuration.json -- Archivo de configuración por defecto
     └── configuration.pro.json -- Propiedades que se sobreescribirán cuando se ejecute en modo producción
├── src -- Código fuente del proyecto
     ├── configuration -- Carpeta para guardar todos los tipos relacionados con la configuración
          └── custom.configuration.ts -- Interfaz de la nuestra configuración personalizada
     └── example -- Carpeta donde vamos a guardar todo lo relacionado con la entidad Example
           ├── example.api.ts -- Archivo donde estarán las definiciones de los objetos de entrada/salida de la API de Example
           ├── example.controller.ts -- Controlador API REST que publicará todos las rutas relacionadas con la entidad Example
           ├── example.service.ts -- Servicio conectado a una MongoDB, que se encargará de todas las operaciones relacionadas con la collection Example
           └── example.shared.ts -- Todas las interfaces, types, enums, etc. compartidas en el proyecto que sean de la entidad Example
├── test -- Carpeta para guardar todos nuestros Test Service
     └── example -- Carpeta de los test relacionados con la entidad Example
           └── example-service.test.ts -- Test service para src/example/example.service.ts
├── node_modules/ -- NPM node_modules
├── package.json -- NPM package.json, con todas las dependencias y scripts necesarios
└── tsconfig.json -- Archivo de configuración Typescript

El script nos va a crear una "entidad" llamada example, y de esta entidad vamos a tener un servicio example.service.ts que se encargará de la collection example en MongoDB y tendremos el controlador example.controller.ts que es el que va a publicar todas las rutas que empiecen por /example/.... Para este ejemplo también es importante el archivo example.api.ts que contiene la definición de los objetos de entrada y salida de todas las rutas de example.

Al ejecutar el comando entre otras cosas ya se nos han instalado todas las dependencias, así que si queremos ya podemos ejecutar el servidor con:

npm start

que iniciaría el servidor como si fuera un entorno de producción, pero para probar 4 cosas es mejor que ejecutemos

npm run dev

lo que hará que se inicie el servidor en modo desarrollo, y se reiniciará cada vez que modifiquemos algún archivo typescript.

Si accedemos a http://localhost:3000/api/documentation nos encontraremos una pantalla como esta:

Aquí lo que nos encontramos es un listado de todas las apis declaradas en el código, con un visualizador de OAS 3 código libre hecho por Swagger, ya veremos en otros posts exactamente a qué se refiere, pero de momento simplemente saber que es un JSON en donde se definen todas las APIs de un servidor, y dónde se indican los objetos de entrada, salida, mensajes de error, etc. es decir, todo lo que puede necesitar un cliente de esa API.

Todo lo que vemos aquí es una representación del código, es decir que si modificamos cualquier cosa, la documentación se va a actualizar. Por ejemplo, si vamos al archivo src/example/example.controller.ts y modificamos:

@Post('/new', { // Aquí hemos agregado /new, es decir que hemos cambiado la url del servicio
  routeSchemas: {
    request: ExampleUpdateRequest,
    response: ExampleIdParam
  }
})
public async create(req: Request<ExampleUpdateRequest>) {
  const example: Example = {
    id: StringUtils.createRandomId(),
    ...req.body
    }
  await this.examlpleServie.create(example);
  return { id: example.id };
}

El cambio se va a compilar en cuanto guardemos el archivo, y si refrescamos la página de la documentación ahora veremos:

Como podemos observar, lo que antes era POST /example, ahora ha pasado a ser POST /example/new, y así con cualquier cosa que modifiquemos en relación a los controladores, de esta manera conseguimos tener una documentación siempre actualizada de nuestros servicios, a la vez que usamos todas la ventajas de un framework a la hora de tener esa velocidad para crear APIs y tranquilidad de estar haciéndolo bien.

Este es el primer post de muchos que tenemos programados hacer en un futuro explicando cada parte en detalle sobre el framework, pero de momento hemos creado una wiki con información sobre las características principales del framework, en la sección en español que se encuentra a la derecha.

Os invitamos a probarlo y abrir una issue en Github si necesitáis ayuda en algo. Cualquier información, ayuda o colaboración es bienvenida. También podéis enviar un mensaje privado a cualquiera de nosotros: sergiolc@plugcore.com ó germanml@plugcore.com