Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 225 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,228 @@ src/main/java/edu/eci/arsw/blueprints
**Bonus**:

- Imagen de contenedor (`spring-boot:build-image`).
- Métricas con Actuator.
- Métricas con Actuator.

---

# Laboratorio #3 – REST API Blueprints
## Escuela Colombiana de Ingeniería – Arquitecturas de Software
**Java 21 / Spring Boot 3.3.9**

---

## 1. Integrantes


- Laura castill: Base de datos, persistencia en PostgreSQL y filtros
- Miguel Sandoval: API REST, manejo de errores, Swagger/OpenAPI y documentación

---

## 2. Arquitectura del Proyecto

El proyecto sigue una arquitectura por capas lógicas, lo que permite cambiar la fuente de persistencia o el mecanismo de exposición de la API sin afectar el resto del sistema:

```
src/main/java/edu/eci/arsw/blueprints
├── model/ # Entidades de dominio: Blueprint, Point, BlueprintId
├── persistence/ # Interfaz BlueprintPersistence + implementaciones (InMemory, Postgres)
├── services/ # Lógica de negocio y orquestación (BlueprintsServices)
├── filters/ # Filtros de procesamiento (Identity, Redundancy, Undersampling)
├── controllers/ # REST Controllers + manejo global de errores (advice)
├── dto/ # Contratos de la API (ApiResponse<T>)
└── config/ # Configuración de Swagger/OpenAPI
```

- Al desacoplar `persistence` de `services` mediante la interfaz `BlueprintPersistence`, fue posible migrar de una implementación en memoria a PostgreSQL sin modificar la lógica de negocio ni el controlador. De igual forma, el `dto.ApiResponse<T>` separa el contrato expuesto al cliente de las entidades JPA del dominio.

---

## 3. Requisitos y Ejecución

### Requisitos
- Java 21
- Maven 3.9+
- Docker y Docker Desktop

### Levantar la base de datos

```bash
docker-compose up -d
```

Esto levanta un contenedor de PostgreSQL 15 (`blueprints-postgres`) en el puerto `5432`, con la base de datos `blueprintsdb`.

### Ejecutar la aplicación

```bash
mvn clean install
mvn spring-boot:run
```

La aplicación arranca en `http://localhost:8080`.

### Cambiar el filtro activo

El filtro de puntos se activa mediante perfiles de Spring, configurado en `application.yml`:

```yaml
spring:
profiles:
active: redundancy # o "undersampling"
```

- `redundancy` → activa `RedundancyFilter` (elimina puntos duplicados consecutivos).
- `undersampling` → activa `UndersamplingFilter` (conserva 1 de cada 2 puntos).

---

## 4. Diseño de la API

### Versionamiento
Todos los endpoints están bajo el path base **`/api/v1/blueprints`**.

### Respuesta uniforme

Todas las respuestas de la API —exitosas o no— siguen la misma estructura, definida en `dto.ApiResponse<T>`:

```java
public record ApiResponse<T>(int code, String message, T data) {}
```

Ejemplo de respuesta exitosa:

```json
{
"code": 200,
"message": "execute ok",
"data": {
"author": "john",
"name": "house",
"points": [{"x": 1, "y": 1}, {"x": 2, "y": 2}]
}
}
```

### Endpoints

| Método | Path | Descripción | Código éxito |
|---|---|---|---|
| GET | `/api/v1/blueprints` | Obtiene todos los blueprints | 200 |
| GET | `/api/v1/blueprints/{author}` | Obtiene los blueprints de un autor | 200 |
| GET | `/api/v1/blueprints/{author}/{bpname}` | Obtiene un blueprint específico | 200 |
| POST | `/api/v1/blueprints` | Crea un nuevo blueprint | 201 |
| PUT | `/api/v1/blueprints/{author}/{bpname}/points` | Agrega un punto a un blueprint existente | 202 |

---

## 5. Manejo de Errores

Se implementó un manejador global de excepciones con `@RestControllerAdvice` (`GlobalExceptionHandler`), que centraliza la traducción de excepciones de negocio a respuestas HTTP consistentes con `ApiResponse<T>`.

| Excepción | Código HTTP | Cuándo ocurre |
|---|---|---|
| `BlueprintNotFoundException` | 404 Not Found | Se consulta un autor/blueprint que no existe |
| `BlueprintPersistenceException` | 400 Bad Request | Se intenta crear un blueprint duplicado |
| `MethodArgumentNotValidException` | 400 Bad Request | El body de la petición no cumple las validaciones (`@NotBlank`, etc.) |
| `Exception` (genérica) | 500 Internal Server Error | Cualquier error no controlado |

Esto evita tener bloques `try/catch` repetidos en el controlador: los métodos declaran `throws` y Spring enruta automáticamente la excepción al manejador correspondiente.

---

## 6. Persistencia en PostgreSQL (Fase 1)

### Modelo de datos

- **`blueprints`**: clave compuesta (`author`, `name`).
- **`blueprint_points`**: tabla de puntos asociada a cada blueprint mediante `blueprint_author` y `blueprint_name`, con orden preservado (`point_order`).

### Configuración de conexión

```yaml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/blueprintsdb
username: postgres
password: postgres
driver-class-name: org.postgresql.Driver
jpa:
database-platform: org.hibernate.dialect.PostgreSQLDialect
hibernate:
ddl-auto: update
show-sql: true
```

> Las credenciales mostradas son las de desarrollo local definidas en `docker-compose.yml`; no se usan en un entorno productivo real.

---

## 7. Filtros de Blueprints

- **`RedundancyFilter`**: elimina puntos duplicados consecutivos de un blueprint antes de devolverlo.
- **`UndersamplingFilter`**: conserva 1 de cada 2 puntos, reduciendo la resolución del trazo.
- Ambos implementan la interfaz `BlueprintsFilter` y se activan mediante los perfiles de Spring `redundancy` y `undersampling` respectivamente, configurables en `application.yml`.

---

## 8. Documentación OpenAPI / Swagger

La documentación de la API se genera automáticamente con `springdoc-openapi`, disponible en:

- Swagger UI: `http://localhost:8080/swagger-ui.html`
- OpenAPI JSON: `http://localhost:8080/v3/api-docs`

Cada endpoint está anotado con `@Operation` y `@ApiResponses`, documentando explícitamente los códigos de éxito y error posibles.

<img width="1793" height="818" alt="Captura de pantalla 2026-08-26 200923" src="https://github.com/user-attachments/assets/3f8ea683-e675-4671-b499-d8258584b197" />


---

## 9. Evidencias de Pruebas

Se implementaron pruebas de la capa web (`BlueprintsAPIControllerTest`) usando `@WebMvcTest` y `MockMvc`, mockeando `BlueprintsServices` para aislar la prueba del controlador de la capa de persistencia real. Se cubren los casos:

- Listado exitoso (200)
- Autor no encontrado (404)
- Consulta de blueprint existente (200)
- Creación exitosa (201)
- Validación de body inválido (400)
- Creación de blueprint duplicado (400)
- Actualización de punto exitosa (202) y sobre blueprint inexistente (404)

Resultado de la ejecución (`mvn test`):

```
Tests run: 9, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
```

<img width="1715" height="317" alt="Captura de pantalla 2026-08-26 201059" src="https://github.com/user-attachments/assets/b7ddd012-0d9e-449f-a270-6e2a5791776c" />


---

## 10. Evidencias Funcionales


<img width="1707" height="875" alt="image" src="https://github.com/user-attachments/assets/b42956ae-76e2-4b18-8a58-70219bea464c" />

<img width="1692" height="530" alt="image" src="https://github.com/user-attachments/assets/eebc19bb-fdb4-4945-b401-7b7579db8e27" />

<img width="1697" height="701" alt="image" src="https://github.com/user-attachments/assets/1aad7aad-b353-4235-a400-bebc47b1bb28" />


---

## 11. Buenas Prácticas Aplicadas

- **Versionamiento de API**: path base `/api/v1/blueprints`, permitiendo evolucionar la API sin romper clientes existentes.
- **Separación de contratos y dominio**: `ApiResponse<T>` como DTO de respuesta, independiente de las entidades JPA.
- **Manejo centralizado de errores**: un único `@RestControllerAdvice` en lugar de `try/catch` repetido en cada endpoint.
- **Documentación automática**: OpenAPI/Swagger generado desde anotaciones, siempre sincronizado con el código.
- **Pruebas automatizadas**: cobertura de la capa web con `MockMvc`, desacoplada de la base de datos real.
- **Persistencia desacoplada**: la interfaz `BlueprintPersistence` permite alternar entre almacenamiento en memoria y PostgreSQL sin tocar la lógica de negocio.

---
18 changes: 18 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: "3.9"

services:
postgres:
image: postgres:15
container_name: blueprints-postgres
restart: unless-stopped
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: blueprintsdb
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data

volumes:
postgres_data:
13 changes: 13 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,24 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Loading