diff --git a/.gitignore b/.gitignore index 564b0a7..a71cd2b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -README.md target/ .mvn/wrapper/maven-wrapper.jar !**/src/main/**/target/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..70787d5 --- /dev/null +++ b/README.md @@ -0,0 +1,305 @@ +# 🍳 MasterChef API + +API REST para la gestión de recetas del programa **Máster Chef Celebrity**, desarrollada con **Spring Boot** y **MongoDB Atlas**. +Este proyecto forma parte de la fase inicial de desarrollo del portal web del programa, donde los televidentes podrán consultar, publicar y gestionar recetas. + +--- + +# 📋 Descripción del Proyecto + +La API permite registrar, consultar, actualizar y eliminar recetas de cocina creadas por: +- Participantes del programa. +- Chefs del jurado. +- Televidentes del público general. + +Cada receta incluye: +- Título +- Lista de ingredientes +- Pasos de preparación +- Autor (con su tipo: participante, chef o televidente) +- Temporada (solo si pertenece a un participante del programa) + +Además, el sistema expone endpoints para: +- Buscar recetas por ingrediente. +- Filtrar recetas según su tipo de autor. +- Consultar recetas por temporada o por número consecutivo. + +--- + +# 🧱 Tecnologías utilizadas + +- **Java 21** +- **Spring Boot 3.5.6** +- **MongoDB Atlas (NoSQL en la nube)** +- **Maven** +- **Swagger (Springdoc OpenAPI)** para documentación +- **JUnit 5** para pruebas unitarias +- **GitHub Actions** para CI/CD +- **Azure App Service** para despliegue + +--- + +# ⚙️ Instrucciones de instalación y ejecución local + +## 🔹 1. Crear proyecto en SpringBoot + +![img.png](docs/imagenes/img.png) + +Y ordenamos las carpetas de tal manera que quede como una arquitectura de capas donde vamos a segmentar las responsabilidades. + +![img_1.png](docs/imagenes/img_1.png) + +Luego empezamos a crear la lógica en cada carpeta para poder realizar las Apis donde: + +**Repository:** manejará la conexión con MongoDB. + +**Service:** contendrá la lógica de negocio (crear, actualizar, buscar, eliminar). + +**Controller:** expondrá los endpoints REST y usará Swagger para documentarlos. + +**Model:** las entidades de la base de datos. + +## 🔹 2. Creamos la base de datos en MongoDB Atlas + +Creamos la base de datos en Atlas ya que es accesible desde cualquier lado incluído azure, gratis, fácil de usar, se conecta con URI y es la mejor opción para el despliegue en azure + swagger. + +![img_2.png](docs/imagenes/img_2.png) + +Y ya por último ponemos la URL en el application.properties para terminar de configurarlo. + +![img_3.png](docs/imagenes/img_3.png) + +## 🔹 3. API con pruebas unitarias + +Una vez ya tenemos las 12 funcionalidades, realizamos las 3 pruebas que nos piden y ejecutamos el comando mvn test. + +![img_4.png](docs/imagenes/img_4.png) + +## 🔹 3. Probamos los request y response por cada Endpoint + +### POST /api/recetas/televidente + +![img_8.png](docs/imagenes/img_8.png) + +![img_9.png](docs/imagenes/img_9.png) + +### POST /api/recetas/participante + +![img_10.png](docs/imagenes/img_10.png) + +![img_11.png](docs/imagenes/img_11.png) + +### POST /api/recetas/chef + +![img_12.png](docs/imagenes/img_12.png) + +![img_13.png](docs/imagenes/img_13.png) + +### GET /api/recetas + +Lista de todas las recetas creadas anteriormente: + +![img_14.png](docs/imagenes/img_14.png) + +### GET /api/recetas/{id} + +![img_15.png](docs/imagenes/img_15.png) + +![img_16.png](docs/imagenes/img_16.png) + +### GET /api/recetas/televidente + +Solo recetas con tipoAutor: TELEVIDENTE + +![img_17.png](docs/imagenes/img_17.png) + +### GET /api/recetas/participante + +Solo recetas con tipoAutor: PARTICIPANTE + +![img_18.png](docs/imagenes/img_18.png) + +### GET /api/recetas/chef + +Solo recetas con tipoAutor: CHEF + +![img_19.png](docs/imagenes/img_19.png) + +### GET /api/recetas/temporada/{numero} + +![img_20.png](docs/imagenes/img_20.png) + +![img_21.png](docs/imagenes/img_21.png) + +### GET /api/recetas/buscar/{nombre} + +![img_22.png](docs/imagenes/img_22.png) + +![img_23.png](docs/imagenes/img_23.png) + +### DELETE /api/recetas/{id} + +![img_24.png](docs/imagenes/img_24.png) + +![img_25.png](docs/imagenes/img_25.png) + +### PUT /api/recetas/{id} + +![img_26.png](docs/imagenes/img_26.png) + +![img_27.png](docs/imagenes/img_27.png) + +Y con eso terminamos de probar las 12 funcionalidades de nuestra API en Swagger. + + +Y comprobamos si se guardó en la base de datos en MongoDB + +![img_28.png](docs/imagenes/img_28.png) + +## 🔹 4. CI/CD con GitHub Actions + +Para garantizar la integración y despliegue continuo del proyecto, se configuraron **pipelines de CI/CD** utilizando **GitHub Actions**. +Este flujo permite automatizar la ejecución de pruebas y el despliegue automático en Azure App Service. + +--- + +### Paso 1. Crear la estructura de GitHub Actions + +Dentro del proyecto, se creó la siguiente ruta: + +``` +.github/ + └── workflows/ + ├── ci.yml + └── deploy.yml +``` + +Esta carpeta le indica a GitHub que debe buscar en ella los archivos YAML que definen los **workflows** (automatizaciones) del repositorio. + +--- + +### Paso 2. Configurar el workflow de Integración Continua (CI) + +El archivo **`ci.yml`** se encarga de compilar el proyecto y ejecutar las pruebas unitarias cada vez que se hace un **push o pull request a la rama `develop`**. + +```yaml +name: CI - MasterChef API + +on: + push: + branches: + - develop + pull_request: + branches: + - develop + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up JDK 21 + uses: actions/setup-java@v3 + with: + java-version: '21' + distribution: 'temurin' + + - name: Build with Maven + run: mvn clean install + + - name: Run tests + run: mvn test +``` + +🔹 **Qué hace este pipeline:** +- Detecta cambios en la rama `develop`. +- Descarga el código del repositorio. +- Instala Java 21 (distribución Temurin). +- Compila el proyecto con Maven. +- Ejecuta todas las pruebas unitarias (`mvn test`). + +✅ Si las pruebas pasan correctamente, GitHub mostrará el workflow en verde. +En caso de fallar, se marcará en rojo y se impedirá el merge a `main`. + +--- + +### Paso 3. Configurar el workflow de Despliegue Continuo (CD) + +El archivo **`deploy.yml`** se encarga de desplegar automáticamente la aplicación en **Azure App Service** cuando se hace **push a la rama `main`**. + +```yaml +name: CD - Deploy to Azure App Service + +on: + push: + branches: + - main + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up JDK 21 + uses: actions/setup-java@v3 + with: + java-version: '21' + distribution: 'temurin' + + - name: Login to Azure + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Build with Maven + run: mvn clean package + + - name: Deploy to Azure Web App + uses: azure/webapps-deploy@v2 + with: + app-name: masterchef + slot-name: production + package: target/*.jar +``` + +🔹 **Qué hace este pipeline:** +- Se activa automáticamente con cualquier cambio en la rama `main`. +- Compila el proyecto (`mvn clean package`). +- Inicia sesión en Azure usando las credenciales almacenadas en `secrets.AZURE_CREDENTIALS`. +- Despliega el archivo `.jar` resultante en el servicio **Azure App Service** (`masterchef-api`). + +--- + +### Paso 4. Crear el secreto de conexión con Azure + +Para permitir que GitHub Actions se comunique con Azure, se generó un **secreto de autenticación**: + +1. En el portal de Azure, se creó una credencial mediante **Azure CLI** o el botón *“Obtener credenciales de publicación”*. +2. En GitHub, se fue a: + `Settings → Secrets and variables → Actions → New repository secret` +3. Se creó un nuevo secreto llamado: + ``` + AZURE_CREDENTIALS + ``` + y se pegó allí el contenido JSON con las credenciales de Azure. + +--- + +### Paso 5. Validar el flujo completo + +- Al hacer un **push o pull request a `develop`**, se ejecuta el workflow **CI**, ejecutando pruebas automáticas. +- Al hacer un **push o merge a `main`**, se activa el **CD**, desplegando automáticamente la aplicación en Azure. +- Una vez finalizado el despliegue, la API queda disponible en la siguiente URL: + + 🔗 **https://masterchef-feaxhgdabggufyb9.westus3-01.azurewebsites.net/swagger-ui/index.html** + +--- + +📄 **Resultado final:** +Con esta configuración, el proyecto cuenta con un flujo de **integración y despliegue continuo totalmente automatizado**, garantizando calidad en el código y actualizaciones instantáneas en el entorno de producción. diff --git a/img.png b/docs/imagenes/img.png similarity index 100% rename from img.png rename to docs/imagenes/img.png diff --git a/img_1.png b/docs/imagenes/img_1.png similarity index 100% rename from img_1.png rename to docs/imagenes/img_1.png diff --git a/img_10.png b/docs/imagenes/img_10.png similarity index 100% rename from img_10.png rename to docs/imagenes/img_10.png diff --git a/img_11.png b/docs/imagenes/img_11.png similarity index 100% rename from img_11.png rename to docs/imagenes/img_11.png diff --git a/img_12.png b/docs/imagenes/img_12.png similarity index 100% rename from img_12.png rename to docs/imagenes/img_12.png diff --git a/img_13.png b/docs/imagenes/img_13.png similarity index 100% rename from img_13.png rename to docs/imagenes/img_13.png diff --git a/img_14.png b/docs/imagenes/img_14.png similarity index 100% rename from img_14.png rename to docs/imagenes/img_14.png diff --git a/img_15.png b/docs/imagenes/img_15.png similarity index 100% rename from img_15.png rename to docs/imagenes/img_15.png diff --git a/img_16.png b/docs/imagenes/img_16.png similarity index 100% rename from img_16.png rename to docs/imagenes/img_16.png diff --git a/img_17.png b/docs/imagenes/img_17.png similarity index 100% rename from img_17.png rename to docs/imagenes/img_17.png diff --git a/img_18.png b/docs/imagenes/img_18.png similarity index 100% rename from img_18.png rename to docs/imagenes/img_18.png diff --git a/img_19.png b/docs/imagenes/img_19.png similarity index 100% rename from img_19.png rename to docs/imagenes/img_19.png diff --git a/img_2.png b/docs/imagenes/img_2.png similarity index 100% rename from img_2.png rename to docs/imagenes/img_2.png diff --git a/img_20.png b/docs/imagenes/img_20.png similarity index 100% rename from img_20.png rename to docs/imagenes/img_20.png diff --git a/img_21.png b/docs/imagenes/img_21.png similarity index 100% rename from img_21.png rename to docs/imagenes/img_21.png diff --git a/img_22.png b/docs/imagenes/img_22.png similarity index 100% rename from img_22.png rename to docs/imagenes/img_22.png diff --git a/img_23.png b/docs/imagenes/img_23.png similarity index 100% rename from img_23.png rename to docs/imagenes/img_23.png diff --git a/img_24.png b/docs/imagenes/img_24.png similarity index 100% rename from img_24.png rename to docs/imagenes/img_24.png diff --git a/img_25.png b/docs/imagenes/img_25.png similarity index 100% rename from img_25.png rename to docs/imagenes/img_25.png diff --git a/img_26.png b/docs/imagenes/img_26.png similarity index 100% rename from img_26.png rename to docs/imagenes/img_26.png diff --git a/img_27.png b/docs/imagenes/img_27.png similarity index 100% rename from img_27.png rename to docs/imagenes/img_27.png diff --git a/img_28.png b/docs/imagenes/img_28.png similarity index 100% rename from img_28.png rename to docs/imagenes/img_28.png diff --git a/img_3.png b/docs/imagenes/img_3.png similarity index 100% rename from img_3.png rename to docs/imagenes/img_3.png diff --git a/img_4.png b/docs/imagenes/img_4.png similarity index 100% rename from img_4.png rename to docs/imagenes/img_4.png diff --git a/img_5.png b/docs/imagenes/img_5.png similarity index 100% rename from img_5.png rename to docs/imagenes/img_5.png diff --git a/img_6.png b/docs/imagenes/img_6.png similarity index 100% rename from img_6.png rename to docs/imagenes/img_6.png diff --git a/img_7.png b/docs/imagenes/img_7.png similarity index 100% rename from img_7.png rename to docs/imagenes/img_7.png diff --git a/img_8.png b/docs/imagenes/img_8.png similarity index 100% rename from img_8.png rename to docs/imagenes/img_8.png diff --git a/img_9.png b/docs/imagenes/img_9.png similarity index 100% rename from img_9.png rename to docs/imagenes/img_9.png diff --git a/pom.xml b/pom.xml index 35011d8..d1696b6 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ org.springframework.boot spring-boot-starter-parent - 3.5.6 + 3.5.6 diff --git a/src/main/java/com/masterchef/recetas/model/Receta.java b/src/main/java/com/masterchef/recetas/model/Receta.java index 0f65763..06a1a65 100644 --- a/src/main/java/com/masterchef/recetas/model/Receta.java +++ b/src/main/java/com/masterchef/recetas/model/Receta.java @@ -1,6 +1,3 @@ -/** - * cd - */ package com.masterchef.recetas.model; import lombok.*; diff --git a/src/test/java/com/masterchef/recetas/service/RecetaServiceTest.java b/src/test/java/com/masterchef/recetas/service/RecetaServiceTest.java index ecb4945..273d448 100644 --- a/src/test/java/com/masterchef/recetas/service/RecetaServiceTest.java +++ b/src/test/java/com/masterchef/recetas/service/RecetaServiceTest.java @@ -43,7 +43,6 @@ void setUp() { @Test void testRegistrarReceta() { - // Simula que Mongo guarda la receta correctamente when(recetaRepository.save(any(Receta.class))).thenReturn(receta); Receta guardada = recetaService.guardarReceta(receta); @@ -57,7 +56,6 @@ void testRegistrarReceta() { @Test void testBuscarPorIngrediente() { - // Simula que en la base existen recetas con "Pollo" when(recetaRepository.findAll()).thenReturn(List.of(receta)); List resultados = recetaService.buscarPorIngrediente("Pollo");