# Crea el proyecto Spring Boot


## Configura el proyecto

Crea un proyecto Spring Boot desde [Spring Initializr](https://start.spring.io)
seleccionando los iniciadores **Spring Web** y **Testcontainers**.

Como alternativa, clona el
[repositorio de la guía](https://github.com/testcontainers/tc-guide-testing-rest-api-integrations-using-wiremock).

Después de generar el proyecto, añade las bibliotecas **REST Assured**, **WireMock** y el
**módulo de Testcontainers WireMock** como dependencias de prueba. Las dependencias clave
en `pom.xml` son:

```xml
<properties>
    <java.version>17</java.version>
    <testcontainers.version>2.0.4</testcontainers.version>
    <wiremock-testcontainers.version>1.0-alpha-13</wiremock-testcontainers.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>testcontainers-junit-jupiter</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.wiremock</groupId>
        <artifactId>wiremock-standalone</artifactId>
        <version>3.6.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.wiremock.integrations.testcontainers</groupId>
        <artifactId>wiremock-testcontainers-module</artifactId>
        <version>${wiremock-testcontainers.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.rest-assured</groupId>
        <artifactId>rest-assured</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
```

Se recomienda usar la BOM (Bill of Materials) de Testcontainers para que no
tengas que repetir la versión para cada dependencia de módulo de Testcontainers.

Esta guía construye una aplicación que gestiona álbumes de video. Una API REST de terceros
maneja los recursos de fotos. Con fines demostrativos, la aplicación utiliza la API pública
[JSONPlaceholder](https://jsonplaceholder.typicode.com/) 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 determinado.
[WireMock](https://wiremock.org/) es una herramienta para construir APIs simuladas (mock).
Testcontainers proporciona un
[módulo de WireMock](https://testcontainers.com/modules/wiremock/) que ejecuta
WireMock como un contenedor Docker.

## Crea los modelos Album y Photo

Crea `Album.java` utilizando Java records:

```java
package com.testcontainers.demo;

import java.util.List;

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

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

## Crea el PhotoServiceClient

Crea `PhotoServiceClient.java`, que utiliza `RestTemplate` para obtener fotos para
un ID de álbum determinado:

```java
package com.testcontainers.demo;

import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
class PhotoServiceClient {

  private final String baseUrl;
  private final RestTemplate restTemplate;

  PhotoServiceClient(
    @Value("${photos.api.base-url}") String baseUrl,
    RestTemplateBuilder builder
  ) {
    this.baseUrl = baseUrl;
    this.restTemplate = builder.build();
  }

  List<Photo> getPhotos(Long albumId) {
    String url = baseUrl + "/albums/{albumId}/photos";
    ResponseEntity<List<Photo>> response = restTemplate.exchange(
      url,
      HttpMethod.GET,
      null,
      new ParameterizedTypeReference<>() {},
      albumId
    );
    return response.getBody();
  }
}
```

La URL base del servicio de fotos se externaliza como una propiedad de configuración. Añade la
siguiente entrada en `src/main/resources/application.properties`:

```properties
photos.api.base-url=https://jsonplaceholder.typicode.com
```

## Crea el endpoint de la API REST

Crea `AlbumController.java`:

```java
package com.testcontainers.demo;

import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestClientResponseException;

@RestController
@RequestMapping("/api")
class AlbumController {

  private static final Logger logger = LoggerFactory.getLogger(
    AlbumController.class
  );

  private final PhotoServiceClient photoServiceClient;

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

  @GetMapping("/albums/{albumId}")
  public ResponseEntity<Album> getAlbumById(@PathVariable Long albumId) {
    try {
      List<Photo> photos = photoServiceClient.getPhotos(albumId);
      return ResponseEntity.ok(new Album(albumId, photos));
    } catch (RestClientResponseException e) {
      logger.error("Failed to get photos", e);
      return new ResponseEntity<>(e.getStatusCode());
    }
  }
}
```

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

```json
{
  "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"
    }
  ]
}
```

