Compartir comentarios
Las respuestas se generan en base a la documentación.

Crear el proyecto Micronaut

Configurar el proyecto

Crea un proyecto Micronaut desde Micronaut Launch seleccionando las características http-client, micronaut-test-rest-assured y testcontainers.

Alternativamente, puedes clonar el repositorio de la guía.

Después de generar el proyecto, agrega las bibliotecas WireMock y Testcontainers WireMock como dependencias de prueba. Las dependencias clave en pom.xml son:

<parent>
    <groupId>io.micronaut.platform</groupId>
    <artifactId>micronaut-parent</artifactId>
    <version>4.1.2</version>
</parent>

<properties>
    <jdk.version>17</jdk.version>
    <micronaut.version>4.1.2</micronaut.version>
    <micronaut.runtime>netty</micronaut.runtime>
</properties>

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>io.micronaut</groupId>
        <artifactId>micronaut-http-client</artifactId>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>io.micronaut</groupId>
        <artifactId>micronaut-http-server-netty</artifactId>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>io.micronaut.serde</groupId>
        <artifactId>micronaut-serde-jackson</artifactId>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>io.micronaut.test</groupId>
        <artifactId>micronaut-test-junit5</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.micronaut.test</groupId>
        <artifactId>micronaut-test-rest-assured</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>testcontainers-junit-jupiter</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>testcontainers</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.wiremock</groupId>
        <artifactId>wiremock-standalone</artifactId>
        <version>3.2.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.wiremock.integrations.testcontainers</groupId>
        <artifactId>wiremock-testcontainers-module</artifactId>
        <version>1.0-alpha-13</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Esta guía construye una aplicación que gestiona álbumes de video. Una API REST de terceros maneja los recursos de fotos. Con fines de demostración, la aplicación utiliza la API pública JSONPlaceholder como servicio de fotos.

La aplicación expone un endpoint GET /api/albums/{albumId} que llama al servicio de fotos para obtener las fotos de un álbum específico. WireMock es una herramienta para construir APIs simuladas (mock APIs). Testcontainers proporciona un módulo de WireMock que ejecuta WireMock como un contenedor Docker.

Crear los modelos Album y Photo

Crea Album.java utilizando Java records. Anota ambos records con @Serdeable para permitir la serialización y deserialización:

package com.testcontainers.demo;

import io.micronaut.serde.annotation.Serdeable;
import java.util.List;

@Serdeable
public record Album(Long albumId, List<Photo> photos) {}

@Serdeable
record Photo(Long id, String title, String url, String thumbnailUrl) {}

Crear el PhotoServiceClient

Micronaut proporciona soporte para clientes HTTP declarativos. Crea una interfaz con un método que obtenga las fotos para un ID de álbum determinado:

package com.testcontainers.demo;

import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.PathVariable;
import io.micronaut.http.client.annotation.Client;
import java.util.List;

@Client(id = "photosapi")
interface PhotoServiceClient {

    @Get("/albums/{albumId}/photos")
    List<Photo> getPhotos(@PathVariable Long albumId);
}

La anotación @Client(id = "photosapi") vincula este cliente a una configuración con nombre. Agrega la siguiente propiedad a src/main/resources/application.properties para establecer la URL base:

micronaut.http.services.photosapi.url=https://jsonplaceholder.typicode.com

Crear el endpoint de la API REST

Crea AlbumController.java:

package com.testcontainers.demo;

import static io.micronaut.scheduling.TaskExecutors.BLOCKING;

import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.PathVariable;
import io.micronaut.scheduling.annotation.ExecuteOn;

@Controller("/api")
class AlbumController {

    private final PhotoServiceClient photoServiceClient;

    AlbumController(PhotoServiceClient photoServiceClient) {
        this.photoServiceClient = photoServiceClient;
    }

    @ExecuteOn(BLOCKING)
    @Get("/albums/{albumId}")
    public Album getAlbumById(@PathVariable Long albumId) {
        return new Album(albumId, photoServiceClient.getPhotos(albumId));
    }
}

Esto es lo que hace este controlador:

  • @Controller("/api") mapea el controlador a la ruta /api.
  • La inyección por constructor proporciona un bean PhotoServiceClient.
  • @ExecuteOn(BLOCKING) descarga las operaciones de E/S bloqueantes en un grupo de hilos separado para que no bloqueen el bucle de eventos.
  • @Get("/albums/{albumId}") mapea el método getAlbumById() a una solicitud HTTP GET.

Este endpoint llama al servicio de fotos para un ID de álbum específico y devuelve una respuesta como:

{
  "albumId": 1,
  "photos": [
    {
      "id": 51,
      "title": "non sunt voluptatem placeat consequuntur rem incidunt",
      "url": "https://via.placeholder.com/600/8e973b",
      "thumbnailUrl": "https://via.placeholder.com/150/8e973b"
    },
    {
      "id": 52,
      "title": "eveniet pariatur quia nobis reiciendis laboriosam ea",
      "url": "https://via.placeholder.com/600/121fa4",
      "thumbnailUrl": "https://via.placeholder.com/150/121fa4"
    }
  ]
}