Saltar al contenido principal

Usa el código generado

Hasta ahora usamos el OpenAPI Generator Gradle Plugin para generar la representación de la OpenAPI Specification (nuestro contrato) en código Java.

build

Pero todavía no estamos usando nada de ese código en nuestra aplicación. Cambiemos eso.

Implementar la interfaz de API generada

Vamos a reescribir el Controller para que implemente la interfaz de API generada.

  1. Eliminá toda la lógica de negocio. Debería quedar medio vacío, así:

    src/main/java/dev/pollito/users_manager/adapter/in/rest/UserController.java
    package dev.pollito.users_manager.adapter.in.rest;

    import lombok.RequiredArgsConstructor;
    import org.springframework.web.bind.annotation.RestController;

    @RestController
    @RequiredArgsConstructor
    public class UserController {
    }
  2. Implementá la interfaz generada y seleccioná los métodos a sobrescribir. Si usas IntelliJ IDEA, presionando CTRL+O en cualquier parte de la clase, vas a ver un popup que te pregunta qué métodos sobrescribir.

    sobrescribir

    Nos interesan findAll() y findById(id:Long).

    Ahora el controlador debería verse algo así:

    src/main/java/dev/pollito/users_manager/adapter/in/rest/UserController.java
    package dev.pollito.users_manager.adapter.in.rest;

    import dev.pollito.users_manager.adapter.in.rest.api.UsersApi;
    import dev.pollito.users_manager.adapter.in.rest.dto.User;
    import lombok.RequiredArgsConstructor;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.RestController;

    import java.util.List;

    @RestController
    @RequiredArgsConstructor
    public class UserController implements UsersApi {
    @Override
    public ResponseEntity<List<User>> findAll() {
    return UsersApi.super.findAll();
    }

    @Override
    public ResponseEntity<User> findById(Long id) {
    return UsersApi.super.findById(id);
    }
    }

    Hacé clic derecho en la clase principal → Run. Luego andá a http://localhost:8080/users. Deberías obtener 501 NOT IMPLEMENTED.

    501 Not Implemented

    Vamos a devolver una lista de Usuarios hardcodeada una vez más.

  3. Inyectá Service y Mapper de nuevo y usalos en findAll().

    src/main/java/dev/pollito/users_manager/adapter/in/rest/UserController.java
    package dev.pollito.users_manager.adapter.in.rest;

    import dev.pollito.users_manager.adapter.in.rest.api.UsersApi;
    import dev.pollito.users_manager.adapter.in.rest.dto.User;
    import dev.pollito.users_manager.adapter.in.rest.mapper.UserMapper;
    import dev.pollito.users_manager.domain.port.in.UserService;
    import lombok.RequiredArgsConstructor;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.RestController;

    import java.util.List;

    @RestController
    @RequiredArgsConstructor
    public class UserController implements UsersApi {
    private final UserService userService;
    private final UserMapper userMapper;

    @Override
    public ResponseEntity<List<User>> findAll() {
    return ResponseEntity.ok(userService.findAll().stream().map(userMapper::map).toList());
    }

    @Override
    public ResponseEntity<User> findById(Long id) {
    return UsersApi.super.findById(id);
    }
    }

    Vas a notar que el IDE nos tira este error:

    no instance(s) of type variable(s) exist so that List<UserResponseDTO> conforms to List<User>
    inference variable T has incompatible bounds:
    equality constraints: List<User>
    lower bounds: List<UserResponseDTO>

    Eso es porque antes de usar OpenAPI Generator Gradle Plugin, UserController devuelve UserResponseDTO (el DTO que escribimos a mano).

    antes de la generación

    Otras carpetas se omiten por simplicidad.

    Pero ahora con OpenAPI Generator Gradle Plugin, UserController está implementando UsersApi, así que debe devolver el DTO generado (User).

    después de la generación

    Otras carpetas se omiten por simplicidad.

  4. Haz que UserMapper mapee al DTO generado.

    package dev.pollito.users_manager.adapter.in.rest.mapper;

    import static org.mapstruct.MappingConstants.ComponentModel.SPRING;

    import dev.pollito.users_manager.domain.model.User;
    import org.mapstruct.Mapper;

    @Mapper(componentModel = SPRING)
    public interface UserMapper {
    dev.pollito.users_manager.adapter.in.rest.dto.User map(User u);
    }
    • Si te sale un error del IDE que dice incompatible return type, hacé un clean y build.

    • Durante la construcción, puede que te salga una advertencia:

      warning: Unmapped target properties: "address, company, phone, profilePictureUrl, website". dev.pollito.users_manager.adapter.in.rest.dto.User map(User u);

      Eso está bien. Vamos a mapear esos valores más adelante.

Hacé clic derecho en la clase principal → Run. Luego andá a http://localhost:8080/users. Deberías obtener la lista con el usuario hardcodeado de nuevo.

respuesta

Próximos pasos

Acá te dejo algo de tarea:

  • Creá un método User findUserById(Long id) en UserService, implementalo en UserServiceImpl, y llamalo en el método ResponseEntity<User> findById(Long id) de UserController.

    • En el método User findUserById(Long id) de UserServiceImpl, sentite libre de lanzar una NotImplementedException. Vamos a hacer una implementación adecuada más adelante.

      src/main/java/dev/pollito/users_manager/domain/service/UserServiceImpl.java
      @Override
      public User findUserById(Long id) {
      throw new NotImplementedException();
      }
  • Commiteá el progreso hasta ahora:

    git add .
    git commit -m "usando código de primary adapter generado a partir de una openapi specification"