Expenses API imagen de cabecera

Expenses API

API
PHP
Docker

Una API REST con la magia de Symfony y API Platform

Os presentamos esta pequeña API de ejemplo con fines didácticos, en esta ocasión hemos usado Symfony 5 como motor central para su desarrollo apoyándonos en API Platform para gestionar todo el apartado REST, para el apartado de infraestructura necesaria para hacer funcionar este proyecto hemos elegido Docker y Docker compose.

Podéis ver el código fuente del proyecto en Gitlab, la documentación técnica en Nextcloud y la propia interfaz de Swagger de la API donde podréis ver y usar los endpoints.

A continuación os vamos a contar qué tecnologías se usan en este proyecto y para qué se usan.

 

Infraestructura

Como os comentaba en el resumen este proyecto se basa en Docker y Docker compose para hacer funcionar la API, si os parece os comento un poco que son y para qué sirven estas tecnologías, si ya las conoces sáltate esta parte y continua más abajo.

 

Expenses API diagrama de infraestructura

 

Docker

Docker es una herramienta que cuando la conocí era un poco escéptico en cuanto a su uso, prefería tener más control sobre los servidores, claro era un novato y no tenía ni idea de cómo se usaba ni lo que era exactamente. Una vez indague más sobre que era exactamente y cómo podía usarla me dí cuenta de que era la bomba, Docker es un virtualizador a fin de cuentas, crea contenedores aislados (o isolados del Spanglish made in yo) para ejecutar un determinado software, por ejemplo un servidor web Nginx, de esta forma no tienes que tenerlo instalado en tu máquina local para usarlo, Docker hace magia y crea un contenedor con una distribución Linux con lo mínimo para que funcione el servidor Nginx.

Docker tiene una gran ventaja para desarrollar software y es la portabilidad, puedo tener la misma infraestructura esté en donde esté, en un equipo con windows, en un equipo con mac, en un equipo con linux, en un servidor.... Esto no tiene precio, además nos evita el tema de: En mi ordenador no me funciona... (o al revés), todos tendremos la misma infraestructura y configuraciones.

 

Docker compose

Docker compose es otra herramienta maravillosa y cuando la conocí es cuando me terminé de enamorar de Docker, ahora sí que sí, Docker compose es un orquestador de contenedores que te facilita la tarea de montar servidores, aplicaciones, etc con Docker, solo tienes que configurar un archivo yml para hacer funcionar tus servidores y relacionarlos (también relacionarlo con tu equipo local) con solo unos parámetros.

 

¿Y qué servidores usa este proyecto?

Como os contaba gracias a la magia de Docker ha sido coser y cantar el brindar de todos los servicios necesarios para hacer correr esta API REST, como hemos elegido Symfony necesitábamos un servidor web, en este caso Nginx porque me encanta como servidor web, otros dos servicios PHP 7 FPM (uno para ejecutar PHP y otro que correrá en segundo plano para consumir colas, esto os lo explicaré un poco más adelante), un servicio de base de datos MySql, un servicio RabbitMQ para gestionar las colas de las notificaciones (en este caso se envían a través de correo) y un servicio MailHog para tener un correo dummy y poder ver las notificaciones sin tener que hacer túneles o montar un servidor de correo entero, recordad que esto es un proyecto de ejemplo con fines educativos.

No os voy a contar que es un servidor web ni php, entiendo que si estás aquí seguro que lo sabes, pero si que me gustaría entrar un poco más a fondo en explicar el tema de las colas porque me parece interesante.

 

Venga... va... cuéntame de qué va eso de las colas

Pues sí, como os comentaba un poco más arriba en este caso hemos elegido RabbitMQ como gestor de colas, no es ni más ni menos que un software de negociación de mensajes, esto significa que recibe los mensajes y los encola hasta que puedan ser enviados por otro servicio, esto es muy interesante cuando queremos hacerlo en un segundo plano y la carga de mensajes pueda ser grande, en esta API tenemos la posibilidad de enviar notificaciones a los integrantes de un grupo y este grupo puede ser de 2 personas o de 2000 y no queremos saturar el servidor en el hilo principal... o si?, bah sé que no queréis eso pillastres jeje.

Por esto tenemos dos servicios PHP, uno para las operaciones en el foreground o primer plano y otro en exclusiva para consumir las colas y enviar los mails con las notificaciones. Como veis es simplemente por temas de escalabilidad y eficiencia, además creo que técnicamente es mejor así.

 

Código, frameworks y librerías

Código fuente

Bien, en este punto vamos a ver todas los frameworks y librerías que han hecho posible crear esta API REST. Como ya hemos mencionado usamos Symfony como base, Symfony es un framework PHP que te ofrece muuuuuchiiiiiiisimas características ya desarrolladas para que no tengas que hacerlo todo desde 0, habrá gente que diga: Ya, pero no tengo el control de muchas cosas..., para esa gente y sin enfados por favor, creo que vives en la web 1.0, ahora no cabe lugar para un desarrollo desde 0 completamente ya que seguro que no serías capaz de realizarlo sin un coste enorme de tiempo, recursos, etc. Lo que se traduce en pasta, aunque lo mismo tu creas un framework (ahí ya no entro). Igualmente, Symfony te provee de muchas cosas prefabricadas que puedes usar y si estas se te quedan cortas hay muchísimos plugins para extender su funcionalidad, de hecho hemos usado unos cuantos, a continuación vamos a ver en detalle todo esto.

 

Symfony

Symfony php framework logo

Symfony se define como un set de componentes PHP reusables y un  framework PHP para proyectos web, en nuestro caso y como os comentábamos es nuestra base, un framework (para quien no lo sepa) es un marco de trabajo, ¿y qué es un marco de trabajo?, pues un conjunto de técnicas y conceptos basada en un software que sirve para que todo sea más homogéneo y fácil de mantener y desarrolla.

En este proyecto hemos usado la versión 5 de este framework, que a día de hoy es la última versión. Este framework se basa en el concepto de MVC (Modelo Vista Controlador) que en este caso no voy explicar en profundidad, pero os dejo un enlace donde lo cuentan, además cuenta con una herramienta que te ahorra mucho tiempo en hacer todas las clases PHP o realizar tareas como vaciar la caché, hablamos del Console Component.

 

Doctrine

Doctrine ORM logo

Symfony se integra muy bien con Doctrine, un ORM (Object Relational Mapping) que se encarga de mapear nuestras clases con la tablas de la base de datos y ofrecernos mucha funcionalidad precocinada sin que tengamos que picar todo el código, por supuesto nosotros podemos extender las operaciones básicas que ofrece Doctrine, pero muchas de las veces esto es una mínima parte del trabajo ya que la mayoría de operaciones se trata de hacer un CRUD (Create, Read, Update, Delete) de cada entidad que disponga nuestra aplicación y esto es justamente lo que te ahorras al usar Doctrine. Además te ofrece una forma fácil de desarrollar versiones de la base de datos, crear toda la estructura de esta y un largo etc de herramientas que te proporciona.

 

API Platform

API Platform logo

Otra de las maravillas que puedes integrar con Symfony es API Platform, es un framework dentro del framework como en la película Inception jejejeje. En este caso lo implementamos para crear todo el apartado REST con muy poco esfuerzo ya que también se integra con Doctrine a través de Symfony por lo que os podéis imaginar que con muy poco código y configuraciones tendremos expuesta nuestra base de datos a través de nuestra API REST. Para empezar tendremos de serie todas las operaciones CRUD que tienes con Doctrine, como os decía sin poner ni un punto y coma de código. Ojo no por esto usaremos todas las operaciones que nos expone, puede ser que el poder crear usuarios no esté expuesto como viene por defecto, para esto podrémos configurar tanto los endpoints como añadir los nuestros personalizados.

Por si fuera poco API Platform integra Swagger que sirve para documentar la API y nos provee de una interfaz web donde podremos ver los endpoints y usarlos muy fácilmente.

 

Ramsey UUID

Ya hemos hablado de frameworks y ahora toca de librerías que cabe destacar, en este caso la que hemos usado para generar los UUID o Universally Unique Identifier es la de Ramsey UUID, son identificadores que nunca se repiten y tienen 36 caracteres (32 si quitas los guiones). Está genial esta librería y siempre la uso en un proyecto Symfony, parece una tontería pero es mucho más seguro tener estos IDs que tener los típicos autoincrementales ya que alguien (o un script) podría ir intentando incrementalmente haciendo pruebas en un endpoint con ids aleatorios (1001...1002...1003) y si hay otro problema de seguridad podría llegar a modificar a un usuario o acceder a sus datos (ojo, podría) y con estos UUIDs sería más complicado añadiendo una capa de seguridad más.

 

Lexik JWT authentication

Esta librería nos va a proveer de una interfaz de autorización mediante JWT (JSON Web Token), gracias a Lexik JWT podremos seguir este estándar para usar en cada petición un token (que no dejan de ser que datos codificados en una cadena de texto) generado por esta librería y así mantener una buena seguridad en nuestra aplicación. Además nos ahorra la gestión del login de nuestra app.

 

PHP League Flysystem

League Flysystem nos ayuda con la subida, edición, eliminación de archivos de una manera super sencilla con apenas cuatro comandos. Desde luego una opción interesante en el momento que necesitas manejar archivos en tu app.

 

Funcionalidad

Expenses API interfaz web Swagger

Bien, ahora os contaré qué es lo que hace esta API, es muy sencilla así que después del todo el anterior tostón que os he dado no va a ser algo que no podáis soportar :).

 

La API está compuesta por varias entidades:

  • Usuarios
  • Grupos de usuarios
  • Categorías de gasto
  • Gastos

 

Usuarios

En esta API tenemos dos tipos de usuarios, los usuarios "normales" (o registrados) y los administradores, siendo el primer usuario registrado el primer administrador, osea que si eres el primer usuario en crearse tendrás el super rol de administrador. La diferencia entre ambos, como ya os imaginaréis, es que el administrador puede acceder y modificar todos los datos del sistema (usuarios, gastos, grupos, categorías) y los usuarios normales solo pueden acceder a sus propios datos o de los que sean dueños (o al grupo que pertenezcan).

Para acceder a cualquier información se deberá hacer login y con el token que nos devuelve el endpoint ya se podrá hacer el resto de peticiones.

 

Grupos

Los usuarios podrán pertenecer a grupos con la ventaja de poder compartir categorías y gastos, todos los usuarios podrán acceder a la información de estos gastos / categorías y podrán editarla.

 

Categorías

Los gastos podrán agruparse mediante categorías y las categorías podrán pertenecer a un usuario o a un grupo de usuarios.

 

Gastos

Los gastos pueden pertenecer a una categoría (de usuario o de grupo) o no, pueden pertenecer a un grupo o no y si estos pertenecen a un grupo se podrá notificar al grupo de usuarios del grupo vía mail.

 

Para finalizar os vuelvo a invitar a ver el código fuente del proyecto en Gitlab, la documentación técnica en Nextcloud y la propia interfaz de Swagger de la API donde podréis ver y usar los endpoints.

 

Agradecimientos

Como especial agradecimiento me gustaría resaltar el curso de Udemy que he seguido para poder desarrollarla y darle las gracias a el tutor que es un gran profesional y eso se nota, muchas gracias Juan González por el gran trabajo que has hecho.

 

Y con todo este "tocho" me despido, así que hasta la próxima y saludos compañeros!!!