From c4f88e4e671a0fa38615ab704a667c1ed2dee536 Mon Sep 17 00:00:00 2001 From: Felipe Calvache Date: Sat, 11 Oct 2025 16:13:12 -0500 Subject: [PATCH 1/2] Editando el README --- .gitignore | 1 - README.md | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 README.md 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..2bbf5d5 --- /dev/null +++ b/README.md @@ -0,0 +1,159 @@ +# 🍳 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](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](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](img_2.png) + +Y ya por último ponemos la URL en el application.properties para terminar de configurarlo. + +![img_3.png](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](img_4.png) + +## 🔹 3. Probamos los request y response por cada Endpoint + +### POST /api/recetas/televidente + +![img_8.png](img_8.png) + +![img_9.png](img_9.png) + +### POST /api/recetas/participante + +![img_10.png](img_10.png) + +![img_11.png](img_11.png) + +### POST /api/recetas/chef + +![img_12.png](img_12.png) + +![img_13.png](img_13.png) + +### GET /api/recetas + +Lista de todas las recetas creadas anteriormente: + +![img_14.png](img_14.png) + +### GET /api/recetas/{id} + +![img_15.png](img_15.png) + +![img_16.png](img_16.png) + +### GET /api/recetas/televidente + +Solo recetas con tipoAutor: TELEVIDENTE + +![img_17.png](img_17.png) + +### GET /api/recetas/participante + +Solo recetas con tipoAutor: PARTICIPANTE + +![img_18.png](img_18.png) + +### GET /api/recetas/chef + +Solo recetas con tipoAutor: CHEF + +![img_19.png](img_19.png) + +### GET /api/recetas/temporada/{numero} + +![img_20.png](img_20.png) + +![img_21.png](img_21.png) + +### GET /api/recetas/buscar/{nombre} + +![img_22.png](img_22.png) + +![img_23.png](img_23.png) + +### DELETE /api/recetas/{id} + +![img_24.png](img_24.png) + +![img_25.png](img_25.png) + +### PUT /api/recetas/{id} + +![img_26.png](img_26.png) + +![img_27.png](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](img_28.png) + + From bdcc06757bf3ca1eb6bda92afc26e74bc3124502 Mon Sep 17 00:00:00 2001 From: Felipe Calvache Date: Sat, 11 Oct 2025 16:33:29 -0500 Subject: [PATCH 2/2] Prueba final CI --- README.md | 198 +++++++++++++++--- img.png => docs/imagenes/img.png | Bin img_1.png => docs/imagenes/img_1.png | Bin img_10.png => docs/imagenes/img_10.png | Bin img_11.png => docs/imagenes/img_11.png | Bin img_12.png => docs/imagenes/img_12.png | Bin img_13.png => docs/imagenes/img_13.png | Bin img_14.png => docs/imagenes/img_14.png | Bin img_15.png => docs/imagenes/img_15.png | Bin img_16.png => docs/imagenes/img_16.png | Bin img_17.png => docs/imagenes/img_17.png | Bin img_18.png => docs/imagenes/img_18.png | Bin img_19.png => docs/imagenes/img_19.png | Bin img_2.png => docs/imagenes/img_2.png | Bin img_20.png => docs/imagenes/img_20.png | Bin img_21.png => docs/imagenes/img_21.png | Bin img_22.png => docs/imagenes/img_22.png | Bin img_23.png => docs/imagenes/img_23.png | Bin img_24.png => docs/imagenes/img_24.png | Bin img_25.png => docs/imagenes/img_25.png | Bin img_26.png => docs/imagenes/img_26.png | Bin img_27.png => docs/imagenes/img_27.png | Bin img_28.png => docs/imagenes/img_28.png | Bin img_3.png => docs/imagenes/img_3.png | Bin img_4.png => docs/imagenes/img_4.png | Bin img_5.png => docs/imagenes/img_5.png | Bin img_6.png => docs/imagenes/img_6.png | Bin img_7.png => docs/imagenes/img_7.png | Bin img_8.png => docs/imagenes/img_8.png | Bin img_9.png => docs/imagenes/img_9.png | Bin pom.xml | 2 +- .../com/masterchef/recetas/model/Receta.java | 3 - .../recetas/service/RecetaServiceTest.java | 2 - 33 files changed, 173 insertions(+), 32 deletions(-) rename img.png => docs/imagenes/img.png (100%) rename img_1.png => docs/imagenes/img_1.png (100%) rename img_10.png => docs/imagenes/img_10.png (100%) rename img_11.png => docs/imagenes/img_11.png (100%) rename img_12.png => docs/imagenes/img_12.png (100%) rename img_13.png => docs/imagenes/img_13.png (100%) rename img_14.png => docs/imagenes/img_14.png (100%) rename img_15.png => docs/imagenes/img_15.png (100%) rename img_16.png => docs/imagenes/img_16.png (100%) rename img_17.png => docs/imagenes/img_17.png (100%) rename img_18.png => docs/imagenes/img_18.png (100%) rename img_19.png => docs/imagenes/img_19.png (100%) rename img_2.png => docs/imagenes/img_2.png (100%) rename img_20.png => docs/imagenes/img_20.png (100%) rename img_21.png => docs/imagenes/img_21.png (100%) rename img_22.png => docs/imagenes/img_22.png (100%) rename img_23.png => docs/imagenes/img_23.png (100%) rename img_24.png => docs/imagenes/img_24.png (100%) rename img_25.png => docs/imagenes/img_25.png (100%) rename img_26.png => docs/imagenes/img_26.png (100%) rename img_27.png => docs/imagenes/img_27.png (100%) rename img_28.png => docs/imagenes/img_28.png (100%) rename img_3.png => docs/imagenes/img_3.png (100%) rename img_4.png => docs/imagenes/img_4.png (100%) rename img_5.png => docs/imagenes/img_5.png (100%) rename img_6.png => docs/imagenes/img_6.png (100%) rename img_7.png => docs/imagenes/img_7.png (100%) rename img_8.png => docs/imagenes/img_8.png (100%) rename img_9.png => docs/imagenes/img_9.png (100%) diff --git a/README.md b/README.md index 2bbf5d5..70787d5 100644 --- a/README.md +++ b/README.md @@ -43,11 +43,11 @@ Además, el sistema expone endpoints para: ## 🔹 1. Crear proyecto en SpringBoot -![img.png](img.png) +![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](img_1.png) +![img_1.png](docs/imagenes/img_1.png) Luego empezamos a crear la lógica en cada carpeta para poder realizar las Apis donde: @@ -63,97 +63,243 @@ Luego empezamos a crear la lógica en cada carpeta para poder realizar las Apis 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](img_2.png) +![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](img_3.png) +![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](img_4.png) +![img_4.png](docs/imagenes/img_4.png) ## 🔹 3. Probamos los request y response por cada Endpoint ### POST /api/recetas/televidente -![img_8.png](img_8.png) +![img_8.png](docs/imagenes/img_8.png) -![img_9.png](img_9.png) +![img_9.png](docs/imagenes/img_9.png) ### POST /api/recetas/participante -![img_10.png](img_10.png) +![img_10.png](docs/imagenes/img_10.png) -![img_11.png](img_11.png) +![img_11.png](docs/imagenes/img_11.png) ### POST /api/recetas/chef -![img_12.png](img_12.png) +![img_12.png](docs/imagenes/img_12.png) -![img_13.png](img_13.png) +![img_13.png](docs/imagenes/img_13.png) ### GET /api/recetas Lista de todas las recetas creadas anteriormente: -![img_14.png](img_14.png) +![img_14.png](docs/imagenes/img_14.png) ### GET /api/recetas/{id} -![img_15.png](img_15.png) +![img_15.png](docs/imagenes/img_15.png) -![img_16.png](img_16.png) +![img_16.png](docs/imagenes/img_16.png) ### GET /api/recetas/televidente Solo recetas con tipoAutor: TELEVIDENTE -![img_17.png](img_17.png) +![img_17.png](docs/imagenes/img_17.png) ### GET /api/recetas/participante Solo recetas con tipoAutor: PARTICIPANTE -![img_18.png](img_18.png) +![img_18.png](docs/imagenes/img_18.png) ### GET /api/recetas/chef Solo recetas con tipoAutor: CHEF -![img_19.png](img_19.png) +![img_19.png](docs/imagenes/img_19.png) ### GET /api/recetas/temporada/{numero} -![img_20.png](img_20.png) +![img_20.png](docs/imagenes/img_20.png) -![img_21.png](img_21.png) +![img_21.png](docs/imagenes/img_21.png) ### GET /api/recetas/buscar/{nombre} -![img_22.png](img_22.png) +![img_22.png](docs/imagenes/img_22.png) -![img_23.png](img_23.png) +![img_23.png](docs/imagenes/img_23.png) ### DELETE /api/recetas/{id} -![img_24.png](img_24.png) +![img_24.png](docs/imagenes/img_24.png) -![img_25.png](img_25.png) +![img_25.png](docs/imagenes/img_25.png) ### PUT /api/recetas/{id} -![img_26.png](img_26.png) +![img_26.png](docs/imagenes/img_26.png) -![img_27.png](img_27.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](img_28.png) +![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");