Skip to content

jhoan636/cannon-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

107 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cannon API 🚀

API de cálculo para proyectiles lanzados de un cañón inspirada en el universo de Star Wars. Permite calcular el ángulo y el tiempo de impacto, registrar resultados y consultar el historial parcial de simulaciones.

🚀 Demo en Vivo

Puedes probar la aplicación desplegada directamente en la nube sin necesidad de instalación, sin embargo, puede demorar unos segundos en cargar inicialmente. Esto se debe a que está alojada en un servicio que pone en reposo las aplicaciones cuando no están en uso para ahorrar recursos. Una vez que la aplicación se activa, el rendimiento debería ser normal

👉 Health Check: cannon-api

👉 Swagger UI: cannon-api

👉 API Docs: cannon-api


📋 Cumplimiento de Requerimientos

☑️ NIVEL 1 - Programa Base

✔️️ Programa en Java que calcula ángulo de disparo según especificaciones de Obi-Wan

✔️ Cálculo de ángulo y tiempo de impacto usando física balística

☑️ NIVEL 2 - API REST

✔️ API REST desplegada en cloud (Render.com)

✔️ Endpoint POST /angle/ que calcula ángulo y tiempo

✔️ Respuesta HTTP 200-OK para cálculos exitosos

✔️ Respuesta HTTP 403-Forbidden para cálculos imposibles

✔️ Estructura de respuesta:

 {"angle": 0.42, "time": "1.50s"}

☑️ NIVEL 3 - Historial y Escalabilidad

✔️ Endpoint GET /angle/history para consultar últimos cálculos

✔️ Estructura de petición:

http://localhost:8091/angle/history?page=0&size=20

✔️ Preparado para fluctuaciones de tráfico (100 - 1M req/s)

✔️ Programación reactiva con WebFlux

✔️ Circuit Breaker, Retry y TimeLimiter para tolerancia a fallos

☑️ BONUS Implementados

✔️ Despliegue en cloud (Render.com)

✔️ Base de datos no relacional (MongoDB Atlas)

✔️ Interfaz gráfica (Swagger UI para consulta de ángulos), (cannon-web frontend con react )

✔️ Tolerancia a fallos con Redis como fallback

✔️ Monitoreo y observabilidad (Actuator + Prometheus)

🧑‍💻 Stack Tecnologías

  • Backend: Java 17 + Spring Boot 3.5
  • Programación: WebFlux (programación reactiva)
  • Base de Datos: MongoDB Atlas (reactivo)
  • Cache/Fallback: Redis
  • Documentación: Swagger (OpenAPI WebFlux)
  • Monitoreo: Spring Boot Actuator + Prometheus + Micrometer
  • Resilencia: Circuit Breaker, Retry y TimeLimiter con Resilience4j.
  • Testing: JUnit 5 + Mockito + Spring WebFlux TestClient
  • Pruebas de carga: Grafana K6
  • Cobertura: JaCoCo (>80%)
  • Contenedores: Docker
  • Cloud: Render.com

📐 Patrones Arquitectónicos

  • Hexagonal Architecture: En este proyecto, la lógica principal de la aplicación está bien separada de todo lo que tiene que ver con la infraestructura (como la base de datos o la web). Esto hace que sea mucho más fácil de probar, mantener y cambiar cualquier parte sin afectar el resto.

  • Arquitectura en Capas: El flujo de la aplicación sigue una estructura clara donde primero llegan las peticiones a los controladores, luego pasan a los servicios de aplicación, después a la lógica de negocio y finalmente a la parte de persistencia, dandole a cada capa su responsabilidad.


🧩 Patrones de Diseño

  • Inyección de Dependencias: Gracias a este patrón, los componentes del sistema estan desacoplados entre sí. Así, si necesitas cambiar algo o hacer pruebas, lo puedes hacer sin problemas.
  • Data Transfer Object (DTO): Nos facilita la transferencia de datos entre capas, evitando exponer entidades internas.
  • Repository: Toda la lógica para acceder a la base de datos está encapsulada en repositorios. Si algún día quiero cambiar de base de datos, lo puedo hacer sin tener que reescribir toda la lógica de negocio.
  • Builder: Facilita la creación de objetos complejos de manera legible.
  • Facade: Si hay subsistemas o procesos complejos, los agrupo detrás de una “fachada” para que desde afuera todo se vea simple y fácil de usar.
  • Circuit Breaker: Implementado con Resilience4j para prevenir llamadas a servicios que están fallando, mejorando la estabilidad del sistema
  • Template Method: Presente en el flujo de calculateAngleAndTime() donde se define la estructura general del algoritmo (calcular → guardar log → retornar resultado), pero permite variaciones en la implementación de cada paso.

🏗️ Arquitectura Propuesta

[ Controller (adapter in) ]
         ↓
[ Application Service ]
         ↓
[ Domain Logic ]
         ↓
[ Adapter out (Mongo Repository) ]
         ↓
[ Redis Cache Service (Fallback) ]

🔧 Fórmulas Físicas Implementadas

La API utiliza las siguientes fórmulas de balística:

Ángulo óptimo: θ = 0.5 * arcsin((d * g) / v²)
Tiempo de vuelo: t = d / (v * cos(θ))

Donde:

  • d = distancia al objetivo (m)
  • v = velocidad inicial del proyectil (m/s)
  • g = aceleración gravitacional (9.81 m/s²)
  • θ = ángulo de disparo (radianes) Validaciones Implementadas:

Velocidad y distancia > 0

Argumento del arco seno ∈ [-1, 1] (físicamente posible)


📦 Instalación y Ejecución Local

🔗 1. Clonar y configurar el entorno

⚡ Ejecuta el siguiente comando para clonar un repositorio Git remoto:

git clone https://github.com/jhoan636/cannon-api.git

⚡ Ejecuta el siguiente comando para entrar al directorio:

cd cannon-api

⚙️ 2. Configura variables de entorno

⚠️ Nota: Antes de continuar, asegúrate de tener una base de datos creada en MongoDB Atlas.

Crear archivo .env en la raíz del proyecto

Variable Descripción
APP_NAME Nombre de la aplicación (se usa en logs o en el header)
PORT Puerto donde escuchará el servidor HTTP
TITLE Título de la API
DESCRIPTION Descripción de la API
VERSION Puerto donde escuchará el servidor HTTP
DATA_CONNECTION_METHOD Protocolo de MongoDB
DATA_SOURCE_USERNAME Usuario de MongoDB Atlas
DATA_SOURCE_PASSWORD Contraseña de MongoDB Atlas
DATA_SOURCE_DOMAIN Dominio del clúster Atlas
DATA_SOURCE_DB Nombre de la base de datos
DATA_PARAMS Parámetros de conexión adicionales
CACHE_TYPE Tipo de caché (redis)
CACHE_HOST Host de Redis
CACHE_PORT Puerto de Redis
CACHE_TIMEOUT Tiempo de espera para operaciones de caché (en ms)
CACHE_LETTUCE_POOL_MAX_ACTIVE Máximo de conexiones activas en el pool de Redis
CACHE_LETTUCE_POOL_MAX_WAIT Tiempo máximo de espera para conexiones a Redis (en ms)
CACHE_LETTUCE_POOL_MAX_IDLE Máximo de conexiones inactivas en el pool de Redis
CACHE_LETTUCE_POOL_MIN_IDLE Mínimo de conexiones inactivas en el pool de Redis

✅ El archivo .env es leído automáticamente gracias a la dependencia dotenv-java

🐳 3. Redis local con Docker

⚠️ Nota: Antes de continuar, asegúrate de tener Docker instalado y corriendo.

Para que Cannon-API funcione correctamente (especialmente el fallback y cache), necesitas tener un servidor Redis corriendo en tu máquina local. La forma más sencilla es usando Docker.

Pasos para levantar Redis con Docker

  1. Abre una terminal y ejecuta:

    docker run -d --name cannon-redis -p 6379:6379 redis:7-alpine

    Esto descargará la imagen oficial de Redis y la levantará en el puerto 6379.

  2. Verifica que Redis está corriendo:

    docker ps

    Deberías ver un contenedor llamado cannon-redis en la lista.

  3. (Opcional) Accede a la consola de Redis:

    docker exec -it cannon-redis redis-cli
  4. Configura tu .env para usar Redis local:

    CACHE_HOST=localhost
    CACHE_PORT=6379
    

⚠️ Nota: Si ya tienes Redis instalado localmente, asegúrate de que no haya conflicto de puertos.

  1. Para detener Redis cuando no lo necesites:

    docker stop cannon-redis
  2. Para eliminar el contenedor:

    docker rm cannon-redis

4. Instalar dependencias y compilar

⚡ Ejecuta el siguiente comando para construir un proyecto Maven:

./mvnw clean package

✅ Esto descargará todo lo necesario y generará el JAR en target/.

⚡ Ejecuta el siguiente comando para iniciar una aplicación Spring Boot:

./mvnw spring-boot:run

5. Verifica que arranque

⚡ Ejecuta el siguiente comando en tu navegador o Postman en estado UP es levando el entorno:

http://localhost:<puerto>/actuator/health   ← indica si la app está viva

🐳 Ejecución con Docker

⚠️ Nota: Antes de continuar, asegúrate de tener Docker instalado y corriendo.

🛠️ 1. Compilar y empaquetar proyecto

Abre tu terminal y navega hasta el directorio raíz del proyecto.

⚡ Ejecuta el siguiente comando:

./mvnw clean package -DskipTests -P docker -f pom.xml

✅ Este comando limpia, compila y empaqueta el proyecto en un JAR, omitiendo pruebas -DskipTests y usando un perfil -P docker que ignora el archivo .env.

🧱 2. Construcción de la Imagen Docker

Asegúrate de tener un archivo Dockerfile en la raíz del proyecto. Este archivo define cómo se construirá la imagen Docker.

⚡ Ejecuta el siguiente comando para construir la imagen:

docker build --platform linux/amd64 -t <usuario-dockerhub>/<nombre-de-la-imagen> .

✅ Este comando crea una imagen Docker basada en tu aplicación. ⚡ Ejecuta el siguiente comando para construir la imagen:

docker run -p <puerto>:<puerto> --env-file .env -v ${PWD}/.env:/app/.env <usuario-dockerhub>/<nombre-de-la-imagen>

🧱 3. Publicación de la Imagen en Docker Hub

⚡ Ejecuta el siguiente comando para inicio sesión en Docker Hub desde la terminal:

docker login

⚡ Ejecuta el siguiente comando para envíar la imagen a tu repositorio en Docker Hub <usuario-dockerhub> con tu nombre de usuario:

docker push <usuario-dockerhub>/<nombre-de-la-imagen>

✅ Esto hará que tu imagen Docker esté disponible públicamente en línea.

🚀 4. Despliegue en Render.com

Crear un Servicio Web

  • Inicia sesión en tu cuenta de Render.com.
  • Haz clic en New > Web Service.
  • Selecciona Docker como el método de despliegue.
  • Ingresa el nombre de tu repositorio en Docker Hub: <usuario-dockerhub>/<nombre-de-la-imagen>
  • Configura las variables de entorno necesarias para tu aplicación.
  • Haz clic en Create para iniciar el despliegue.

4.2 Despliegue Manual mediante Deploy Hook

⚡ Ejecuta el siguiente comando, usa el deploy hook para activar despliegues automáticos:

curl -X POST https://api.render.com/deploy/srv-csgeg0lumphs73b48veg?key={key}

➡️ Reemplaza {key} con tu clave real de deploy hook proporcionada por Render.

⚡ Ejecuta el siguiente comando como Alternativamente, si estás usando Windows, podrías tener un script como este:

cmd /c deploy.render.cmd

Este comando debería ejecutar internamente el comando curl anterior.


📊 Documentación de la API (Swagger)

Se integra SpringDoc OpenAPI para exponer la documentación de la API en formato OpenAPI 3.0 y Swagger UI

  • OpenAPI JSON/YAML: GET /v3/api-docs

⚡ Ejecuta el siguiente comando para acceder al documento OpenAPI en formato JSON:

http://localhost:<puerto>/v3/api-docs
  • Swagger UI: GET /swagger-ui.html

⚡ Ejecuta el siguiente comando para abrir la interfaz gráfica de Swagger UI:

http://localhost:<puerto>/swagger-ui/index.html#/

📊 Monitoreo y observabilidad

📈 1. Metrics

Nos permite exponer información en esta caso cannon.calculateImpact que nos brinda la siguiente información

Campo Significado
COUNT Número total de veces que se llamó el método.
TOTAL_TIME Tiempo total que ha tomado todas las ejecuciones del método.
MAX Tiempo máximo que tomó una ejecución individual.

⚡ Ejecuta el siguiente comando, para ver las métricas:

http://localhost:<puerto>/actuator/metrics

⚠️ Nota: Antes de continuar, asegúrate de tener mínimo una petición al endpoints.

⚡ Ejecuta el siguiente comando, para ver métrica personalizada:

http://localhost:<puerto>/actuator/metrics/cannon.calculateImpact

🔍 2. Observabilidad

Esta aplicación expone métricas vía Spring Boot Actuator + Micrometer podremos usar Prometheus + Grafana.

⚠️ Nota: Antes de continuar, asegúrate de tener descargado Prometheus y Grafana en local en caso de usar Docker te dejo el paso a

paso PROMETHEUS y GRAFANA con DOCKER

⚡ Ejecuta el siguiente comando, para ver las métricas:

http://localhost:<puerto>/actuator/prometheus

✅ Métricas en formato Prometheus para scraping.

⚡ Ejecuta el siguiente comando, para acceder a Grafana en:

http://localhost:3000

(Usuario y contraseña por defecto: admin / admin)

⚡ Ejecuta el siguiente comando, para agrega Prometheus como Data Source:

http://localhost:9090

En el siguiente comando puedes ver los llamados el tiempo de ejecución y los servicios a los cuales se les aplica circuitbreaker .

⚡ Ejecuta el siguiente comando, para metricas de resilience4j circuitbreaker:

http://localhost:8091/actuator/metrics/resilience4j.circuitbreaker.calls

✅ Crea o importa un Dashboard para visualizar las métricas de Spring Boot.

🎯 Análisis de Cobertura de Código con JaCoCo

JaCoCo es una herramienta estándar y de código abierto para medir la cobertura del código en aplicaciones Java

¿Cómo generar y ver el reporte?

⚡ Ejecuta el siguiente comando, para generar reporte:

./mvnw clean test

⚡ Ejecuta el siguiente comando, verificar la Cobertura (y fallar el build si es baja):

./mvnw clean verify

📄 Localiza el reporte:

Una vez finalizada la ejecución, JaCoCo habrá generado un reporte HTML en la siguiente ruta:

target/site/jacoco/index.html

🎯 Analiza el reporte:

Abre el archivo index.html en tu navegador. Verás un resumen de la cobertura por paquete. Puedes navegar dentro de cada paquete y clase para ver en detalle qué líneas de código están cubiertas (verde), parcialmente cubiertas (amarillo) o no cubiertas (rojo).

🔍 Ejemplo de reporte:

Reporte

⚠️ Tolerancia a fallos

  • Circuit Breaker: Si MongoDB falla repetidamente, se abre el circuito y se evita sobrecargar el servicio.
  • Retry: Reintenta automáticamente guardar logs hasta 3 veces antes de activar el fallback.
  • TimeLimiter: Si la operación tarda más de 2 segundos, se cancela y activa el fallback.
  • Fallback a Redis: Si no es posible guardar en MongoDB, el log se almacena temporalmente en Redis y se reintenta periódicamente.

🏃‍♂️ Pruebas de Carga

La aplicación está preparada para manejar fluctuaciones de tráfico entre 100 y 1M req/s mediante:

  • Programación Reactiva (WebFlux)
  • Conexiones No Bloqueantes
  • Pool de Conexiones Optimizado
  • Cache y Fallbacks

Ejemplo con K6

import http from 'k6/http';

export let options = {
  stages: [
    { duration: '30s', target: 100 },
    { duration: '1m', target: 1000 },
    { duration: '30s', target: 0 },
  ],
};

export default function() {
  const payload = JSON.stringify({
    velocity: 1000,
    distance: 1500
  });
  
  http.post('http://localhost:8091/angle', payload, {
    headers: { 'Content-Type': 'application/json' },
  });
}

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors