Spring Boot

SpringBoot

Tutorial SpringBoot: Controlador REST reactivo basado en anotaciones

Aprende a programar un API REST reactiva en Spring WebFlux sobre Spring Boot desarrollando controladores REST reactivos basados en anotaciones utilizando tipos Flux y Mono.

Aprende SpringBoot GRATIS y certifícate

Métodos GET usando repositorio reactivo

En Spring WebFlux, los controladores reactivos permiten manejar solicitudes de manera asíncrona y no bloqueante. Para implementar métodos GET que interactúen con un repositorio reactivo, utilizamos las anotaciones estándar de Spring y las clases Flux y Mono para manejar flujos de datos reactivos.

Supongamos que tenemos una entidad Producto y un repositorio reactivo ProductoRepository que extiende de ReactiveCrudRepository:

public interface ProductoRepository extends ReactiveCrudRepository<Producto, String> {
    Flux<Producto> findByCategoria(String categoria);
}

En un controlador reactivo, podemos definir métodos para obtener uno o varios productos. Por ejemplo, para obtener todos los productos:

@RestController
@RequestMapping("/productos")
public class ProductoController {

    private final ProductoRepository productoRepository;

    public ProductoController(ProductoRepository productoRepository) {
        this.productoRepository = productoRepository;
    }

    @GetMapping
    public Flux<Producto> obtenerTodos() {
        return productoRepository.findAll();
    }
}

En este ejemplo, el método obtenerTodos devuelve un Flux de Producto, representando un flujo reactivo de productos. La anotación @GetMapping sin especificar una ruta adicional se asocia con la ruta base /productos.

Para obtener un producto por su identificador, podemos definir:

@GetMapping("/{id}")
public Mono<Producto> obtenerPorId(@PathVariable String id) {
    return productoRepository.findById(id);
}

Aquí, obtenerPorId devuelve un Mono de Producto, que emitirá el producto si se encuentra o completará vacío si no existe.

Si queremos filtrar productos por una propiedad, como la categoría, utilizamos parámetros de consulta:

@GetMapping("/buscar")
public Flux<Producto> buscarPorCategoria(@RequestParam String categoria) {
    return productoRepository.findByCategoria(categoria);
}

En este caso, el método buscarPorCategoria recibe un parámetro de solicitud categoria y devuelve un Flux con los productos que coinciden.

Es importante destacar que al devolver Flux y Mono, Spring WebFlux maneja automáticamente la suscripción y la publicación de los datos en el cuerpo de la respuesta HTTP. Además, al utilizar los repositorios reactivos de Spring Data, obtenemos una integración fluida con las bases de datos que soportan operaciones no bloqueantes.

Para manejar escenarios donde el producto no existe, podemos utilizar operadores reactivos como switchIfEmpty y devolver una respuesta adecuada:

@GetMapping("/{id}")
public Mono<ResponseEntity<Producto>> obtenerPorId(@PathVariable String id) {
    return productoRepository.findById(id)
            .map(producto -> ResponseEntity.ok(producto))
            .switchIfEmpty(Mono.just(ResponseEntity.notFound().build()));
}

En este ejemplo, al envolver el Mono en un ResponseEntity, podemos controlar más fácilmente el código de estado HTTP y devolver un 404 Not Found si el producto no se encuentra.

También podemos manejar flujos infinitos o streamings de datos. Por ejemplo, si queremos emitir productos en tiempo real:

@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Producto> streamProductos() {
    return productoRepository.findAll();
}

Al especificar produces = MediaType.TEXT_EVENT_STREAM_VALUE, indicamos que este endpoint emitirá un flujo de eventos del lado del servidor (Server-Sent Events).

Al usar estas técnicas, aprovechamos al máximo las capacidades de programación reactiva en Spring Boot 3, creando aplicaciones eficientes y escalables.

Métodos POST, PUT y PATCH usando repositorio reactivo

En Spring WebFlux, los controladores reactivos permiten manejar solicitudes HTTP de manera asíncrona y no bloqueante. Al trabajar con métodos POST, PUT y PATCH, utilizamos los repositorios reactivos para interactuar con la base de datos de forma eficiente.

Supongamos que tenemos una entidad Producto y un repositorio reactivo ProductoRepository que extiende ReactiveCrudRepository:

public interface ProductoRepository extends ReactiveCrudRepository<Producto, String> {
    // Métodos personalizados si es necesario
}

Manejo de solicitudes POST

Para crear un nuevo Producto, definimos un método en el controlador reactivo que maneje las solicitudes POST:

@RestController
@RequestMapping("/productos")
public class ProductoController {

    private final ProductoRepository productoRepository;

    public ProductoController(ProductoRepository productoRepository) {
        this.productoRepository = productoRepository;
    }

    @PostMapping
    public Mono<ResponseEntity<Producto>> crearProducto(@RequestBody Producto producto) {
        return productoRepository.save(producto)
                .map(productoGuardado -> ResponseEntity
                        .created(URI.create("/productos/" + productoGuardado.getId()))
                        .body(productoGuardado));
    }
}

En este ejemplo, el método crearProducto recibe un objeto Producto en el cuerpo de la solicitud. Utilizamos el repositorio reactivo para guardar el producto en la base de datos y devolvemos un ResponseEntity con el código de estado 201 Created y la ubicación del nuevo recurso.

Es importante validar el objeto recibido. Podemos utilizar anotaciones de Bean Validation en la clase Producto y agregar @Valid en el método:

@PostMapping
public Mono<ResponseEntity<Producto>> crearProducto(@Valid @RequestBody Producto producto) {
    // ...
}

Manejo de solicitudes PUT

El método PUT se utiliza para reemplazar completamente un recurso existente. En un entorno reactivo, debemos asegurarnos de que el recurso existe antes de actualizarlo:

@PutMapping("/{id}")
public Mono<ResponseEntity<Producto>> actualizarProducto(@PathVariable String id, @Valid @RequestBody Producto producto) {
    return productoRepository.findById(id)
            .flatMap(productoExistente -> {
                producto.setId(id);
                return productoRepository.save(producto);
            })
            .map(productoActualizado -> ResponseEntity.ok(productoActualizado))
            .defaultIfEmpty(ResponseEntity.notFound().build());
}

En este método, buscamos el Producto por su identificador. Si existe, lo actualizamos y guardamos los cambios. Si no se encuentra, devolvemos una respuesta 404 Not Found.

Manejo de solicitudes PATCH

El método PATCH se utiliza para actualizaciones parciales de un recurso. Dado que en Java no existe un mecanismo estándar para aplicar parches, podemos recibir un Map con las propiedades a actualizar:

@PatchMapping("/{id}")
public Mono<ResponseEntity<Producto>> actualizarProductoParcial(@PathVariable String id, @RequestBody Map<String, Object> campos) {
    return productoRepository.findById(id)
            .flatMap(productoExistente -> {
                campos.forEach((key, value) -> {
                    Field field = ReflectionUtils.findField(Producto.class, key);
                    if (field != null) {
                        field.setAccessible(true);
                        Object valorConvertido = conversionService.convert(value, field.getType());
                        ReflectionUtils.setField(field, productoExistente, valorConvertido);
                    }
                });
                return productoRepository.save(productoExistente);
            })
            .map(productoActualizado -> ResponseEntity.ok(productoActualizado))
            .defaultIfEmpty(ResponseEntity.notFound().build());
}

En este ejemplo, utilizamos ReflectionUtils para actualizar dinámicamente los campos del Producto. Es esencial manejar con cuidado este enfoque, ya que puede introducir problemas de seguridad. Se recomienda validar y sanitizar los datos recibidos.

Manejo de errores y validaciones

En aplicaciones reactivas, el manejo de errores es fundamental. Podemos utilizar un ControllerAdvice reactivo para capturar excepciones y devolver respuestas adecuadas:

@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Mono<ResponseEntity<Map<String, String>>> handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map<String, String> errores = ex.getBindingResult().getFieldErrors().stream()
                .collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
        return Mono.just(ResponseEntity.badRequest().body(errores));
    }

    // Otros manejadores de excepciones
}

Con este enfoque, si la validación falla, devolvemos una respuesta con los errores detallados.

Uso de Mono y operaciones reactivas

Es fundamental comprender que al trabajar con repositorios reactivos, las operaciones como save, findById y delete retornan Monos o Fluxes. Al encadenar estas operaciones, podemos aprovechar los operadores reactivos para manejar flujos de datos de manera elegante.

Por ejemplo, si queremos asegurarnos de que no exista un producto con el mismo nombre antes de guardarlo:

@PostMapping
public Mono<ResponseEntity<Producto>> crearProducto(@Valid @RequestBody Producto producto) {
    return productoRepository.findByNombre(producto.getNombre())
            .flatMap(productoExistente -> Mono.error(new ResponseStatusException(HttpStatus.CONFLICT, "El producto ya existe")))
            .switchIfEmpty(productoRepository.save(producto)
                .map(productoGuardado -> ResponseEntity
                        .created(URI.create("/productos/" + productoGuardado.getId()))
                        .body(productoGuardado))
            );
}

Aquí, utilizamos flatMap, switchIfEmpty y manejamos errores con ResponseStatusException para controlar el flujo de la operación.

Actualizaciones condicionales

En ocasiones, es necesario realizar actualizaciones condicionales basadas en ciertos criterios. Podemos combinar operadores reactivos para lograrlo:

@PutMapping("/{id}")
public Mono<ResponseEntity<Producto>> actualizarProductoSiActivo(@PathVariable String id, @Valid @RequestBody Producto producto) {
    return productoRepository.findById(id)
            .filter(Producto::isActivo)
            .flatMap(productoExistente -> {
                producto.setId(id);
                return productoRepository.save(producto);
            })
            .map(productoActualizado -> ResponseEntity.ok(productoActualizado))
            .defaultIfEmpty(ResponseEntity.status(HttpStatus.FORBIDDEN).build());
}

En este caso, solo actualizamos el producto si está activo, devolviendo un 403 Forbidden en caso contrario.

Métodos DELETE usando repositorio reactivo

En Spring WebFlux, los controladores reactivos permiten manejar solicitudes de manera asíncrona y no bloqueante. Para implementar métodos DELETE que interactúen con un repositorio reactivo, utilizamos las anotaciones estándar de Spring y las clases Mono para manejar operaciones reactivas de eliminación.

Supongamos que tenemos una entidad Producto y un repositorio reactivo ProductoRepository que extiende ReactiveCrudRepository:

public interface ProductoRepository extends ReactiveCrudRepository<Producto, String> {
    // Métodos personalizados si es necesario
}

Eliminación de un producto por ID

Para eliminar un producto por su identificador, definimos un método en el controlador que maneje las solicitudes DELETE:

@RestController
@RequestMapping("/productos")
public class ProductoController {

    private final ProductoRepository productoRepository;

    public ProductoController(ProductoRepository productoRepository) {
        this.productoRepository = productoRepository;
    }

    @DeleteMapping("/{id}")
    public Mono<ResponseEntity<Void>> eliminarProducto(@PathVariable String id) {
        return productoRepository.findById(id)
                .flatMap(productoExistente ->
                        productoRepository.delete(productoExistente)
                                .then(Mono.just(new ResponseEntity<Void>(HttpStatus.NO_CONTENT)))
                )
                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }
}

En este ejemplo, el método eliminarProducto busca el producto por su ID utilizando findById. Si el producto existe, se elimina llamando a delete y se devuelve una respuesta con el código de estado 204 No Content. Si no se encuentra, se devuelve una respuesta 404 Not Found. El uso de then permite encadenar acciones de forma reactiva, asegurando que la respuesta solo se envíe después de completar la eliminación.

Eliminación de todos los productos

Si deseamos proporcionar una operación para eliminar todos los productos, podemos definir:

@DeleteMapping
public Mono<ResponseEntity<Void>> eliminarTodosLosProductos() {
    return productoRepository.deleteAll()
            .then(Mono.just(new ResponseEntity<Void>(HttpStatus.NO_CONTENT)));
}

Aquí, deleteAll elimina todos los registros de la entidad Producto. Una vez completada la operación, devolvemos una respuesta con el estado 204 No Content. Es importante usar then para asegurarnos de que la respuesta se envíe después de finalizar la eliminación.

Manejo de errores y control de flujo reactivo

Al trabajar con operaciones reactivas, el manejo de errores y el control del flujo son esenciales. Por ejemplo, si queremos manejar excepciones durante la eliminación, podemos utilizar el operador onErrorResume:

@DeleteMapping("/{id}")
public Mono<ResponseEntity<Void>> eliminarProducto(@PathVariable String id) {
    return productoRepository.findById(id)
            .flatMap(productoExistente ->
                    productoRepository.delete(productoExistente)
                            .then(Mono.just(new ResponseEntity<Void>(HttpStatus.NO_CONTENT)))
            )
            .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND))
            .onErrorResume(error -> Mono.just(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)));
}

Con onErrorResume, capturamos cualquier error que ocurra durante la operación y devolvemos una respuesta de error apropiada.

Eliminación condicional

Podemos implementar una eliminación condicional basada en ciertos criterios. Por ejemplo, eliminar un producto solo si está inactivo:

@DeleteMapping("/{id}")
public Mono<ResponseEntity<Void>> eliminarProductoSiInactivo(@PathVariable String id) {
    return productoRepository.findById(id)
            .filter(producto -> !producto.isActivo())
            .flatMap(productoInactivo ->
                    productoRepository.delete(productoInactivo)
                            .then(Mono.just(new ResponseEntity<Void>(HttpStatus.NO_CONTENT)))
            )
            .switchIfEmpty(Mono.just(new ResponseEntity<>(HttpStatus.FORBIDDEN)));
}

En este caso, utilizamos filter para comprobar si el producto no está activo. Si cumple la condición, procedemos a eliminarlo; de lo contrario, devolvemos una respuesta 403 Forbidden.

Uso de eliminaciones en bloque

Si necesitamos eliminar múltiples productos basados en un criterio, podemos utilizar métodos personalizados en el repositorio reactivo:

public interface ProductoRepository extends ReactiveCrudRepository<Producto, String> {
    Flux<Producto> findByCategoria(String categoria);
    Mono<Void> deleteByCategoria(String categoria);
}

Implementamos el método deleteByCategoria y en el controlador:

@DeleteMapping("/categoria/{categoria}")
public Mono<ResponseEntity<Void>> eliminarPorCategoria(@PathVariable String categoria) {
    return productoRepository.deleteByCategoria(categoria)
            .then(Mono.just(new ResponseEntity<Void>(HttpStatus.NO_CONTENT)));
}

Este método elimina todos los productos pertenecientes a una categoría específica. Al usar operaciones reactivas, garantizamos que la eliminación sea eficiente y no bloqueante.

Consideraciones de concurrencia y consistencia

Al eliminar recursos en aplicaciones reactivas, es fundamental considerar la concurrencia y mantener la consistencia de los datos. Por ejemplo, si otro proceso modifica un producto antes de su eliminación, podríamos implementar un control optimista mediante versiones:

@DeleteMapping("/{id}")
public Mono<ResponseEntity<Void>> eliminarProductoConControl(@PathVariable String id, @RequestHeader("If-Match") String version) {
    return productoRepository.findById(id)
            .filter(producto -> producto.getVersion().equals(version))
            .flatMap(productoExistente ->
                    productoRepository.delete(productoExistente)
                            .then(Mono.just(new ResponseEntity<Void>(HttpStatus.NO_CONTENT)))
            )
            .switchIfEmpty(Mono.just(new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED)));
}

En este ejemplo, utilizamos el encabezado If-Match para recibir la versión del producto. Solo se eliminará si la versión coincide, evitando conflictos. Si no coincide, devolvemos un 412 Precondition Failed.

Uso de métodos HTTP idempotentes

El método DELETE es idempotente, lo que significa que múltiples solicitudes idénticas deberían tener el mismo efecto que una sola. Por lo tanto, si intentamos eliminar un recurso que ya no existe, es recomendable devolver un 204 No Content en lugar de un 404 Not Found:

@DeleteMapping("/{id}")
public Mono<ResponseEntity<Void>> eliminarProductoIdempotente(@PathVariable String id) {
    return productoRepository.deleteById(id)
            .then(Mono.just(new ResponseEntity<Void>(HttpStatus.NO_CONTENT)))
            .onErrorResume(DataAccessException.class, e -> Mono.just(new ResponseEntity<>(HttpStatus.NO_CONTENT)));
}

Aquí, usamos deleteById, que devuelve un Mono<Void>. Si el ID no existe, la operación sigue siendo exitosa desde la perspectiva del cliente, y devolvemos 204 No Content.

Integración con seguridad y autorización

En entornos productivos, es común restringir las operaciones de eliminación a usuarios con permisos específicos. Podemos usar anotaciones de Spring Security para proteger nuestros endpoints:

@DeleteMapping("/{id}")
@PreAuthorize("hasRole('ADMIN')")
public Mono<ResponseEntity<Void>> eliminarProducto(@PathVariable String id) {
    // Implementación del método
}

La anotación @PreAuthorize verifica que el usuario tenga el rol ADMIN antes de permitir la operación.

Buenas prácticas en operaciones DELETE reactivas

  • Validación previa: Antes de eliminar, es recomendable verificar que el recurso existe y que cumple ciertas condiciones.
  • Manejo de excepciones: Utilizar operadores reactivos para capturar y manejar errores, proporcionando respuestas significativas al cliente.
  • Consistencia de datos: Implementar controles para evitar inconsistencias, especialmente en operaciones concurrentes.
  • Uso de Mono y Flux: Aprovechar las capacidades reactivas para encadenar operaciones y manejar flujos de datos eficientemente.
  • Documentación de la API: Utilizar herramientas como OpenAPI para documentar los endpoints y proporcionar información clara sobre las respuestas y códigos de estado.

Al seguir estas prácticas, garantizamos que nuestras operaciones DELETE con repositorios reactivos en Spring Boot 3 sean robustas, eficientes y seguras.

Aprende SpringBoot GRATIS online

Ejercicios de esta lección Controlador REST reactivo basado en anotaciones

Evalúa tus conocimientos de esta lección Controlador REST reactivo basado en anotaciones con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

API Query By Example (QBE)

Spring Boot
Test

Identificadores y relaciones JPA

Spring Boot
Puzzle

Borrar datos de base de datos

Spring Boot
Test

Web y Test Starters

Spring Boot
Puzzle

Métodos find en repositorios

Spring Boot
Test

Controladores Spring MVC

Spring Boot
Código

Inserción de datos

Spring Boot
Test

CRUD Customers Spring MVC + Spring Data JPA

Spring Boot
Proyecto

Backend API REST con Spring Boot

Spring Boot
Proyecto

Controladores Spring REST

Spring Boot
Código

Uso de Spring con Thymeleaf

Spring Boot
Puzzle

API Specification

Spring Boot
Puzzle

Registro de usuarios

Spring Boot
Test

Crear entidades JPA

Spring Boot
Código

Asociaciones en JPA

Spring Boot
Test

Asociaciones de entidades JPA

Spring Boot
Código

Integración con Vue

Spring Boot
Test

Consultas JPQL

Spring Boot
Código

Open API y cómo agregarlo en Spring Boot

Spring Boot
Puzzle

Uso de Controladores REST

Spring Boot
Puzzle

Repositorios reactivos

Spring Boot
Test

Inyección de dependencias

Spring Boot
Test

Introducción a Spring Boot

Spring Boot
Test

CRUD y JPA Repository

Spring Boot
Puzzle

Inyección de dependencias

Spring Boot
Código

Vista en Spring MVC con Thymeleaf

Spring Boot
Test

Servicios en Spring

Spring Boot
Código

Operadores Reactivos

Spring Boot
Puzzle

Configuración de Vue

Spring Boot
Puzzle

Entidades JPA

Spring Boot
Test

Integración con Angular

Spring Boot
Test

API Specification

Spring Boot
Test

API Query By Example (QBE)

Spring Boot
Puzzle

Controladores MVC

Spring Boot
Test

Anotaciones y mapeo en JPA

Spring Boot
Puzzle

Consultas JPQL con @Query en Spring Data JPA

Spring Boot
Test

Repositorios Spring Data

Spring Boot
Test

Inyección de dependencias

Spring Boot
Puzzle

Data JPA y Mail Starters

Spring Boot
Test

Configuración de Angular

Spring Boot
Puzzle

Controladores Spring REST

Spring Boot
Test

Configuración de Controladores MVC

Spring Boot
Puzzle

Consultas JPQL con @Query en Spring Data JPA

Spring Boot
Puzzle

Actualizar datos de base de datos

Spring Boot
Test

Verificar token JWT en peticiones

Spring Boot
Test

Login de usuarios

Spring Boot
Test

Integración con React

Spring Boot
Test

Configuración de React

Spring Boot
Puzzle

Todas las lecciones de SpringBoot

Accede a todas las lecciones de SpringBoot y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A Spring Boot

Spring Boot

Introducción Y Entorno

Spring Boot Starters

Spring Boot

Introducción Y Entorno

Inyección De Dependencias

Spring Boot

Introducción Y Entorno

Controladores Spring Mvc

Spring Boot

Spring Web

Vista En Spring Mvc Con Thymeleaf

Spring Boot

Spring Web

Controladores Spring Rest

Spring Boot

Spring Web

Open Api Y Cómo Agregarlo En Spring Boot

Spring Boot

Spring Web

Servicios En Spring

Spring Boot

Spring Web

Clientes Resttemplate Y Restclient

Spring Boot

Spring Web

Rxjava En Spring Web

Spring Boot

Spring Web

Crear Entidades Jpa

Spring Boot

Persistencia Spring Data

Asociaciones De Entidades Jpa

Spring Boot

Persistencia Spring Data

Repositorios Spring Data

Spring Boot

Persistencia Spring Data

Métodos Find En Repositorios

Spring Boot

Persistencia Spring Data

Inserción De Datos

Spring Boot

Persistencia Spring Data

Actualizar Datos De Base De Datos

Spring Boot

Persistencia Spring Data

Borrar Datos De Base De Datos

Spring Boot

Persistencia Spring Data

Consultas Jpql Con @Query En Spring Data Jpa

Spring Boot

Persistencia Spring Data

Api Query By Example (Qbe)

Spring Boot

Persistencia Spring Data

Api Specification

Spring Boot

Persistencia Spring Data

Repositorios Reactivos

Spring Boot

Persistencia Spring Data

Introducción E Instalación De Apache Kafka

Spring Boot

Mensajería Asíncrona

Crear Proyecto Con Apache Kafka

Spring Boot

Mensajería Asíncrona

Creación De Producers

Spring Boot

Mensajería Asíncrona

Creación De Consumers

Spring Boot

Mensajería Asíncrona

Kafka Streams En Spring Boot

Spring Boot

Mensajería Asíncrona

Introducción A Spring Webflux

Spring Boot

Reactividad Webflux

Spring Data R2dbc

Spring Boot

Reactividad Webflux

Controlador Rest Reactivo Basado En Anotaciones

Spring Boot

Reactividad Webflux

Controlador Rest Reactivo Funcional

Spring Boot

Reactividad Webflux

Operadores Reactivos Básicos

Spring Boot

Reactividad Webflux

Operadores Reactivos Avanzados

Spring Boot

Reactividad Webflux

Cliente Reactivo Webclient

Spring Boot

Reactividad Webflux

Introducción A Spring Security

Spring Boot

Seguridad Con Spring Security

Seguridad Basada En Formulario En Mvc Con Thymeleaf

Spring Boot

Seguridad Con Spring Security

Registro De Usuarios

Spring Boot

Seguridad Con Spring Security

Login De Usuarios

Spring Boot

Seguridad Con Spring Security

Verificar Token Jwt En Peticiones

Spring Boot

Seguridad Con Spring Security

Seguridad Jwt En Api Rest Spring Web

Spring Boot

Seguridad Con Spring Security

Seguridad Jwt En Api Rest Reactiva Spring Webflux

Spring Boot

Seguridad Con Spring Security

Autenticación Y Autorización Con Anotaciones

Spring Boot

Seguridad Con Spring Security

Testing Unitario De Componentes Y Servicios

Spring Boot

Testing Con Spring Test

Testing De Repositorios Spring Data Jpa

Spring Boot

Testing Con Spring Test

Testing Controladores Spring Mvc Con Thymeleaf

Spring Boot

Testing Con Spring Test

Testing Controladores Rest Con Json

Spring Boot

Testing Con Spring Test

Testing De Aplicaciones Reactivas Webflux

Spring Boot

Testing Con Spring Test

Testing De Seguridad Spring Security

Spring Boot

Testing Con Spring Test

Testing Con Apache Kafka

Spring Boot

Testing Con Spring Test

Integración Con Angular

Spring Boot

Integración Frontend

Integración Con React

Spring Boot

Integración Frontend

Integración Con Vue

Spring Boot

Integración Frontend

Accede GRATIS a SpringBoot y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Creación API REST
  • Reactividad en API REST
  • Conexión controlador con repositorios
  • Operadores reactivos
  • Gestión de errores en controladores reactivos