Skip to content

aortizsm/api-ddd

Repository files navigation

API REST con Arquitectura DDD - Mantenimiento de Usuarios

API REST completa para gestión de usuarios implementada con Domain-Driven Design (DDD) en TypeScript y MySQL.

📚 Propósito Educativo

Este proyecto está diseñado específicamente para aprender y entender Domain-Driven Design (DDD). Cada archivo contiene comentarios detallados explicando:

  • Por qué se usa cada patrón
  • Qué problema resuelve
  • Cómo se relaciona con DDD
  • Mejores prácticas aplicadas

🏗️ Arquitectura DDD

El proyecto sigue una arquitectura en capas basada en DDD:

src/
├── domain/              # Capa de Dominio (Núcleo del negocio)
│   ├── entities/        # Entidades (User)
│   ├── value-objects/   # Value Objects (UserId, Email, UserName)
│   ├── repositories/    # Interfaces de repositorios
│   ├── services/        # Servicios de dominio
│   └── exceptions/      # Excepciones del dominio
│
├── application/         # Capa de Aplicación (Casos de uso)
│   ├── use-cases/       # Casos de uso (CreateUser, GetUser, etc.)
│   ├── dtos/            # Data Transfer Objects
│   └── mappers/         # Mappers entre capas
│
├── infrastructure/      # Capa de Infraestructura (Detalles técnicos)
│   ├── database/        # Conexión y configuración de BD
│   │   ├── migrations/  # Migraciones de Sequelize
│   │   ├── seeders/     # Seeders de datos de prueba
│   │   └── connection.ts
│   └── repositories/    # Implementaciones de repositorios
│
├── presentation/        # Capa de Presentación (API REST)
│   ├── controllers/     # Controladores HTTP
│   ├── routes/          # Definición de rutas
│   ├── middlewares/     # Middlewares de Express
│   └── validators/      # Validadores de entrada
│
├── shared/              # Código compartido
│   ├── Result.ts        # Patrón Result para manejo de errores
│   └── Guard.ts         # Validaciones reutilizables
│
└── server.ts            # Punto de entrada y Composition Root

🎯 Conceptos DDD Implementados

1. Capas de Arquitectura

  • Domain: Lógica de negocio pura, independiente de tecnología
  • Application: Orquestación de casos de uso
  • Infrastructure: Detalles de implementación (BD, APIs externas)
  • Presentation: Adaptadores para la interfaz (REST API)

2. Building Blocks

  • Entities: User (con identidad única)
  • Value Objects: UserId, Email, UserName (inmutables, sin identidad)
  • Aggregates: User actúa como Aggregate Root
  • Repositories: Abstracción de persistencia
  • Domain Services: Lógica que no pertenece a entidades

3. Patrones Aplicados

  • Dependency Inversion: Las capas dependen de abstracciones
  • Repository Pattern: Abstracción de persistencia
  • Use Case Pattern: Un caso de uso = una operación de negocio
  • Factory Methods: Creación controlada de objetos
  • Result Pattern: Manejo funcional de errores
  • Guard Clauses: Validaciones defensivas

🚀 Instalación y Configuración

Prerrequisitos

  • Node.js (v16 o superior)
  • MySQL (v5.7 o superior)
  • npm o yarn

Paso 1: Instalar dependencias

npm install

Paso 2: Configurar variables de entorno

Copia el archivo .env.example a .env:

cp .env.example .env

Edita el archivo .env con tus credenciales de MySQL:

PORT=3000
NODE_ENV=development

DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=tu_password
DB_NAME=ddd_users_db

Paso 3: Crear la base de datos

Opción A: Usando Sequelize (Recomendado)

# Crear la base de datos manualmente primero
mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS ddd_users_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

# Ejecutar migraciones y seeders
npm run db:setup

Opción B: Usando el script SQL directo

# Conecta a MySQL
mysql -u root -p

# Ejecuta el script
source src/infrastructure/database/schema.sql

Paso 4: Iniciar el servidor

Modo desarrollo (con auto-reload):

npm run dev

Modo producción:

npm run build
npm start

El servidor estará disponible en: http://localhost:3000

�️ Comandos de Base de Datos (Sequelize)

Migraciones

# Ejecutar todas las migraciones pendientes
npm run db:migrate

# Revertir la última migración
npm run db:migrate:undo

# Revertir todas las migraciones
npm run db:migrate:undo:all

Seeders

# Ejecutar todos los seeders (insertar datos de prueba)
npm run db:seed

# Revertir todos los seeders (eliminar datos de prueba)
npm run db:seed:undo

Setup completo

# Ejecutar migraciones + seeders en un solo comando
npm run db:setup

Usuarios de prueba incluidos

El seeder crea 15 usuarios con diferentes perfiles:

  • Usuarios activos e inactivos
  • Diferentes rangos de edad (13-95 años)
  • Nombres con caracteres especiales
  • IDs predecibles para pruebas

Algunos IDs de ejemplo:

  • 550e8400-e29b-41d4-a716-446655440001 - Juan Pérez
  • 550e8400-e29b-41d4-a716-446655440002 - María García
  • 550e8400-e29b-41d4-a716-446655440003 - Carlos López (inactivo)

�📖 API Endpoints

Health Check

GET /

Crear Usuario

POST /api/users
Content-Type: application/json

{
  "name": "Juan Pérez",
  "email": "juan.perez@example.com",
  "age": 25
}

Obtener Todos los Usuarios

GET /api/users

Obtener Usuario por ID

GET /api/users/{id}

Actualizar Usuario

PUT /api/users/{id}
Content-Type: application/json

{
  "name": "Juan Carlos Pérez",
  "email": "juancarlos@example.com",
  "age": 26,
  "isActive": true
}

Eliminar Usuario

DELETE /api/users/{id}

Nota: El borrado es lógico (soft delete). El usuario no se elimina físicamente; se marca con deleted_at. Las lecturas (GET) excluyen usuarios con deleted_at definido.

🧪 Ejemplos de Uso

Crear un usuario

curl -X POST http://localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{
    "name": "María García",
    "email": "maria.garcia@example.com",
    "age": 30
  }'

Obtener todos los usuarios

curl http://localhost:3000/api/users

Actualizar un usuario

curl -X PUT http://localhost:3000/api/users/550e8400-e29b-41d4-a716-446655440001 \
  -H "Content-Type: application/json" \
  -d '{
    "name": "María García López",
    "age": 31
  }'

Eliminar (soft delete) un usuario

curl -X DELETE http://localhost:3000/api/users/550e8400-e29b-41d4-a716-446655440001

Después del borrado, GET /api/users y GET /api/users/{id} ya no mostrarán ese usuario. La fila permanece en la BD con deleted_at establecido para auditoría.

🔍 Entendiendo el Flujo DDD

Flujo de una petición POST /api/users

  1. Presentation Layer (userRoutes.ts)

    • Recibe la petición HTTP
    • Ejecuta validación con validateCreateUser
    • Llama al controlador
  2. Presentation Layer (UserController.ts)

    • Extrae el DTO del body
    • Llama al Use Case correspondiente
  3. Application Layer (CreateUserUseCase.ts)

    • Recibe el DTO
    • Lo convierte a entidad de dominio usando UserMapper
    • Valida reglas de negocio con UserDomainService
    • Persiste usando el repositorio
    • Retorna DTO de respuesta
  4. Domain Layer

    • Value Objects: Validan email y nombre
    • Entity: User se crea con factory method
    • Domain Service: Verifica que el email sea único
  5. Infrastructure Layer (MySQLUserRepository.ts)

    • Recibe la entidad User
    • La convierte a formato de BD
    • Ejecuta INSERT en MySQL

Inversión de Dependencias en Acción

// Domain Layer define la INTERFAZ (abstracción)
interface IUserRepository {
  save(user: User): Promise<void>;
}

// Application Layer DEPENDE de la abstracción
class CreateUserUseCase {
  constructor(private repo: IUserRepository) {}
}

// Infrastructure Layer IMPLEMENTA la abstracción
class MySQLUserRepository implements IUserRepository {
  save(user: User): Promise<void> { /* ... */ }
}

// Composition Root CONECTA todo
const repository = new MySQLUserRepository();
const useCase = new CreateUserUseCase(repository);

Beneficio: Podemos cambiar MySQL por PostgreSQL sin tocar el dominio.

🎓 Conceptos Clave para Estudiar

1. Entidades vs Value Objects

Entidad (User):

  • Tiene identidad única (UserId)
  • Mutable (puede cambiar con el tiempo)
  • Se compara por ID

Value Object (Email):

  • Sin identidad
  • Inmutable
  • Se compara por valor

2. Aggregate Root

User es un Aggregate Root porque:

  • Define un límite transaccional
  • Protege invariantes del agregado
  • Es el punto de entrada para operaciones

3. Repository Pattern

Abstrae la persistencia:

// En lugar de escribir SQL directamente
db.query("SELECT * FROM users WHERE id = ?", [id]);

// Usamos el repositorio
userRepository.findById(userId);

4. Use Cases

Cada Use Case = Una operación que un usuario puede hacer:

  • CreateUserUseCase: "Como usuario, quiero registrarme"
  • GetUserByIdUseCase: "Como admin, quiero ver un usuario"

5. Result Pattern

Maneja errores sin excepciones:

const nameResult = UserName.create("Juan");
if (nameResult.isFailure) {
  return Result.fail(nameResult.getError());
}
const name = nameResult.getValue();

🛠️ Tecnologías Utilizadas

  • TypeScript: Tipado estático y características avanzadas
  • Express.js: Framework web minimalista
  • MySQL: Base de datos relacional
  • mysql2: Driver de MySQL para Node.js
  • uuid: Generación de IDs únicos
  • dotenv: Gestión de variables de entorno

📝 Mejores Prácticas Implementadas

  1. SOLID Principles

    • Single Responsibility
    • Open/Closed
    • Liskov Substitution
    • Interface Segregation
    • Dependency Inversion
  2. Clean Code

    • Nombres descriptivos
    • Funciones pequeñas y enfocadas
    • Comentarios explicativos
    • Separación de concerns
  3. Type Safety

    • Uso extensivo de TypeScript
    • Interfaces bien definidas
    • Validación en tiempo de compilación
  4. Error Handling

    • Excepciones de dominio tipadas
    • Middleware centralizado de errores
    • Mensajes claros y accionables

🔐 Validaciones Implementadas

Nivel 1: Presentación (HTTP)

  • Campos requeridos
  • Tipos de datos
  • Longitudes básicas

Nivel 2: Dominio (Value Objects)

  • Formato de email RFC 5321
  • Nombres con caracteres válidos
  • Edad en rango válido

Nivel 3: Entidad

  • Invariantes del agregado
  • Reglas de negocio complejas

🚧 Posibles Mejoras (Para Aprender Más)

  1. Paginación: Implementar en GetAllUsersUseCase
  2. Eventos de Dominio: Para comunicación desacoplada
  3. CQRS: Separar modelos de lectura y escritura
  4. Event Sourcing: Guardar eventos en lugar de estado
  5. Testing: Unit tests, integration tests
  6. Autenticación: JWT, OAuth
  7. Documentación: Swagger/OpenAPI
  8. Logging: Winston, Morgan
  9. Monitoreo: Prometheus, Grafana

📚 Recursos para Aprender DDD

  • Libro: "Domain-Driven Design" - Eric Evans
  • Libro: "Implementing Domain-Driven Design" - Vaughn Vernon
  • Artículos: Martin Fowler's blog
  • Cursos: Pluralsight, Udemy

🤝 Contribuir

Este es un proyecto educativo. Siéntete libre de:

  • Hacer fork
  • Agregar features siguiendo DDD
  • Mejorar documentación
  • Compartir con otros desarrolladores

📄 Licencia

ISC

👨‍💻 Autor

Desarrollador web senior especializado en Node.js, DDD y arquitectura de software.


¡Disfruta aprendiendo DDD! 🎉

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published