FlightBooking - Clean Architecture API
FlightBooking es una API REST desarrollada en .NET 8, que permite buscar vuelos, reservarlos y recuperar reservas existentes. Este proyecto está diseñado como una prueba técnica que ha sido transformada en un ejemplo profesional y público, ideal para portafolios. Se ha creado siguiendo principios de arquitectura limpia, CQRS, separación de responsabilidades y buenas prácticas profesionales.
Repositorio
Puedes explorar el código fuente completo en este link
Tecnologías y librerías utilizadas
| Tecnología |
Propósito |
| .NET 8 |
Framework principal de backend |
| ASP.NET Core |
Motor de la API REST |
| MediatR |
Implementación de CQRS para separar Commands y Queries |
| EF Core |
ORM para persistencia en base de datos |
| SQLite |
Motor de base de datos ligero para entorno de desarrollo |
| AutoMapper |
Mapeo entre DTOs y modelos internos |
| FluentValidation |
Validaciones a nivel de DTO y de reglas de negocio |
| Swagger (Swashbuckle) |
Exploración y documentación de la API |
| xUnit + Moq + FluentAssertions |
Tests unitarios |
Estructura del proyecto
El proyecto está dividido en múltiples class libraries siguiendo los principios de Clean Architecture.
- Domain: Entidades de dominio (Booking, Passenger, Contact).
- Application: Commands, Queries, Handlers, Interfaces, lógica de negocio.
- Application.DTO: Modelos de entrada/salida para la API.
- Application.Adapters: Mapeo entre DTOs y Commands/Queries.
- Persistence: Configuración de EF Core, Repositorios, UoW, DbContext.
- ExternalApis: Clientes HTTP a APIs externas (reemplazado por JSON local).
- Api: Punto de entrada, controladores, middleware, Swagger.
Principios aplicados
Clean Architecture
- Capas bien definidas y dependencias unidireccionales (las capas externas dependen de las internas, nunca al revés).
- Dominios independientes de frameworks, infraestructura y librerías externas.
- Uso de interfaces para inyectar comportamientos en lugar de implementaciones directas.
CQRS
- Separación entre Commands (mutaciones) y Queries (lecturas).
- MediatR actúa como mediador entre la API y la lógica de aplicación.
SOLID
- Single Responsibility en cada clase.
- Dependency Inversion mediante interfaces.
- Open/Closed para futuras extensiones.
Flujo de ejecución
- El usuario realiza una petición a la API (Search, Create, Retrieve).
- El Controller la delega a un Adapter, que:
- Valida el DTO usando FluentValidation.
- Mapea a un Command o Query usando AutoMapper.
- El Handler ejecuta la lógica de negocio.
- Consulta el ApiGateway (para búsqueda de vuelos) o el Repository (para persistencia).
- Ejecuta validaciones de reglas de negocio.
- Usa Builders para construir objetos de salida.
- El resultado es devuelto al Adapter, que lo transforma en DTO de respuesta y lo devuelve al Controller.
Repositorios y Persistencia
- Repositorio genérico (RepositoryBase) para operaciones comunes (Add, GetById, Delete).
- Repositorio específico (BookingRepository) para lógica adicional de Booking.
- Se implementó un Unit of Work para garantizar atomicidad y persistencia coherente.
- La base de datos es SQLite, ubicada en
Cheap.Flights.Api/app.db, ideal para entorno local.
Dataset estático
- En lugar de consumir una API externa, se optó por almacenar los vuelos en un JSON estático dentro del proyecto.
- La llamada HTTP fue reemplazada por deserialización directa (System.Text.Json) del archivo
flights.json.
Validaciones
- DTOs validados con FluentValidation para formato, campos requeridos, longitud, etc.
- Commands validados a mano para reglas de negocio.
- Para testeo, la validación de fechas fue comentada, ya que el dataset contiene vuelos antiguos.
Middleware y manejo de errores
- Middleware personalizado para capturar excepciones:
- ValidationException, BusinessRuleException, ExternalApiException, NotFoundException.
- Se implementaron logs en consola (Console.WriteLine) para trazabilidad.
- Se documentó que la intención era usar Serilog con sink a archivo.
Tests unitarios
- Builders (CreateBookingResultBuilder, RetrieveBookingResultBuilder).
- Adapters y sus validaciones.
- Handlers principales (SearchFlightQueryHandler, CreateBookingCommandHandler).
- Tests de validaciones extensas y reglas complejas pendientes.
- Tests de integración y logging también documentados como mejoras.
Limitaciones y mejoras pendientes
- Logger profesional (Serilog).
- Validaciones completas de DTOs y negocio.
- Tests de integración.
- Logging del cuerpo de la request entrante.
- Filtro global de respuesta homogénea para errores.
- Enriquecer Swagger con todos los posibles códigos de respuesta (ProducesResponseType).
Ruta del dataset local
El archivo flights.json se encuentra en:
src/FlightBooking.Api/Data/flights.json
Este archivo es usado para simular la respuesta de la API externa.
Base de datos
- La base de datos
app.db se genera automáticamente al ejecutar la app.
- Está ubicada en la raíz del proyecto
FlightBooking.Api.
- El esquema se aplica automáticamente con
DbContext.Database.Migrate().
Está ignorada en Git, pero se puede inspeccionar con:
DB Browser for SQLite - https://sqlitebrowser.org/
Autor
Creado por Tiberiu Tasnadi — con cariño y pasión por el código limpio.