0% encontró este documento útil (0 votos)
4 vistas174 páginas

1 - Spring 03 02 Boot Rest

spring boot
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
4 vistas174 páginas

1 - Spring 03 02 Boot Rest

spring boot
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 174

Spring Framework

DESARROLLO JAVA AGIL


Unidad 03

BÁSICO
Boot Rest
CURSOS DE
DESARROLLO
O Objetivos
¿Qué voy a a aprender?

• Saber cómo se procesa una petición Web


• Saber definir un API Rest
• Saber definir rutas dentro de la aplicación
• Saber manejar parámetros en una ruta y
controlador
• Saber manejar el valor devuelto
• Saber elegir el estado a devolver
• Saber acceder a los modelos desde los
controladores

3
Spring Avanzado www.cursosdedesarrollo.com
I Índice de Contenidos
¿Cómo voy a aprenderlo?

1. Introducción
2. Controladores
3. Testing
4. Api Rest
5. Testing Rest
6. ResponseEntity
7. Testing ResponseEntity
8. ControllerAdvice
9. Swagger OpenApi
10.HATEOAS
11.Conclusiones

4
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

Para la generación de un Api Rest será


necesario generar el proyecto en el Spring
Inicializr

https://start.spring.io/

5
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

Al crear el proyecto podemos elegir el gestor de


dependencias y procesos: Gradle ó Maven

6
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

También podremos elegir el lenguaje con el que


queremos trabajar: Java, Kotlin o Groovy

7
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

La versión de Spring Boot: bien las últimas


versiones estables, Milestones ó Snapshots

8
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

En el apartado de Project Metadata podemos


elegir: Group ID, Artifact ID, nombre, descripción,
paquete principal de la aplicación, el sistema de
empaquetado (jar o war) y la versión mínima de
Java (8, 11, 17, ...)

9
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

En el apartado de Dependencias podremos


buscar las dependencias o starters que
queramos añadir a nuestro proyecto

10
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

Dentro de las dependencias de desarrollo estaría


bien meter las siguientes: Spring Boot DevTools,
Lombok, Actuator

11
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

De cara a manejar las peticiones Web con un


API Rest: Rest Repositories, Spring Rest Docs,
Rest Repositories Hal Explorer y Spring
HATEOAS

12
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

Para la conexión a una base de datos relacional


usaremos: Spring Data JPA, y los Drivers de
BBDD como por ejemplo H2 y/o MySQL

13
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

Una vez introducidas todas las dependencias


pulsaremos el botón de Generate y nos
descargaremos el proyecto en formato zip

14
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

Descomprimiremos el fichero zip en nuestro


disco duro y lo abriremos con nuestro IDE
favorito

15
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

Respecto a los IDE’s recomendamos los


siguientes: IntelliJ, NetBeans y Eclipse for JEE
Developers

16
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

Una vez abierto el proyecto con nuestro IDE


debería detectar el proyecto Maven y cargar
apropiadamente las bibliotecas del proyecto

17
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

Si queremos arrancar el proyecto podremos


ejecutar el goal de maven spring-boot:run que
debería ejecutar la aplicación web en la url por
defecto:

http://localhost:8080/

18
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Configuración del Proyecto

Si queremos ejecutar el comando a mano


pondríamos:

mvn spring-boot:run

19
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Maven webapp

La estructura básica del proyecto webapp nos


permitirá gestionar el código de la aplicación en
la carpeta src/main/java

20
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Maven webapp

Si usamos otro lenguaje debería aparecer en la


carpeta /src/main

21
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Maven webapp

El directorio con los ficheros de configuración de


la aplicación prinicipal está en
/src/main/resources

22
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Maven webapp

Y los ficheros de distribución web podríamos


colocarlos en la carpeta
/src/main/webapp que luego será el contenido
del directorio de despliegue dentro del fichero
WAR que generaremos

23
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Maven webapp

Dentro de la carpeta webapp podemos tener


acceso al directorio WEB-INF y al web.xml o
fichero de despliegue de la aplicación web

24
Spring Avanzado www.cursosdedesarrollo.com
1 Introducción
Maven webapp

El funcionamiento de Spring Boot automatiza la


mayor parte de las configuraciones de la
aplicación web java que arranca

25
Spring Avanzado www.cursosdedesarrollo.com
1

26
Spring Avanzado www.cursosdedesarrollo.com
2 Controladores
@Controller

Para empezar a gestionar las peticiones


necesitaremos una clase controladora deberá
estar dentro del paquete principal de la
aplicación

27
Spring Avanzado www.cursosdedesarrollo.com
2 Controladores
@Controller

Si estuviéramos usando el API de Web MVC


meteríamos una anotación de tipo @Controller

28
Spring Avanzado www.cursosdedesarrollo.com
2 Controladores
@Controller

@Controller
public class HelloController {
protected final Log logger = LogFactory.getLog(getClass());
@RequestMapping(value="/hello.htm")
public ModelAndView handleRequest(HttpServletRequest
request, HttpServletResponse response)
throws ServletException, IOException {
logger.info(“devolviendo la vista hello.jsp”);
return new ModelAndView(“hello.jsp");
}
}

29
Spring Avanzado www.cursosdedesarrollo.com
2 Controladores
@Controller

Al finy al cabo deberíamos hacernos una idea de


cuáles serían las clases que debemos gestionar
dentro de nuestra aplicación dentro de la
arquitectura de Spring Boot

30
Spring Avanzado www.cursosdedesarrollo.com
2

31
Spring Avanzado www.cursosdedesarrollo.com
2 Controladores
@RestController

Para el manejo de los servicios rest


@RestController esto nos permitirá gestionar el
intercambio de información que venga del cliente
y hacia el cliente

32
Spring Avanzado www.cursosdedesarrollo.com
2 Controladores
@RestController

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MiRestController {
@RequestMapping("/")
public String welcome() {//Welcome page, non-rest
return "Welcome to RestTemplate Example.";
}
}

33
Spring Avanzado www.cursosdedesarrollo.com
2 Controladores
@RestController

En este caso estaríamos definiendo un


controlador Rest con la anotación
@RestController delante de la clase

34
Spring Avanzado www.cursosdedesarrollo.com
2 Controladores
@RestController

Y por otro lado estaríamos definiendo una ruta


mediante la anotación @RequestMapping(“/”)
justo delante del método que queremos asociar

35
Spring Avanzado www.cursosdedesarrollo.com
2 Controladores
@RestController

Indicando que queremos devolver una String con


un contenido específico

36
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

Lo primero que debemos saber es que el


proyecto generado por Spring Inicializr ya incluye
varias dependencias de Testing

37
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

Entre ellas destaca el spring-boot-starter-test que


es la dependencia principal de testing para los
proyectos spring boot que suele añadirse por
defecto aunque no la elijamos en la generación
del proyecto

38
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

Los test de nuestro proyecto deberíamos


colocarlos en la carpeta /src/test/java y serían
clases cuyo nombre terminan por Test o Tests

39
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

Vemos un ejemplo sencillo que suele venir con


la plantilla de proyecto

40
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ApiRestJpaApplicationTests {

@Test
void contextLoads() {
}

41
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

En el ejemplo podemos ver que estamos usando


de base las dependencias de Junit 5, la
anotación @SpringBootTest y la anotación
@Test de Junit 5

42
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

La anotación @SpringBootTest lo que hará será


arrancar la aplicación antes de ejecutar cualquier
prueba definida con la anotación @Test

43
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

Como siempre si queremos arrancar las pruebas


mediante maven deberemos ejecutar el goal test
o ejecutar directamente el:

mvn test

44
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

Veamos ahora un ejemplo un poco más práctico


de una comprobación de la carga del controlador
que hemos definido con anterioridad

45
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

import static org.assertj.core.api.Assertions.assertThat;


import org.junit.jupiter.api.Test;
import
org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class SmokeTest {
@Autowired
private MiRestController controller;

@Test
public void miRestControllerLoads() throws Exception {
assertThat(controller).isNotNull();
}
}

46
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

En este caso lo que estaremos haciendo es


comprobando que el controlador se inicializa
apropiadamente sin llegar a ser Null

47
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

Para poder hacer esta comprobación


necesitamos realizar un par de pasos previos,
primero definiendo un atributo en la clase del
controlador que queremos probar, metiendo justo
delante la anotación @Autowired para que lo
inicialice una manera similar a como lo hacemos
en Spring

48
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

Para depsués definir un @Test de Junit 5 que


haga uso de los Asserts de org.assertJ

https://assertj.github.io/doc/

49
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

En esta caso usamos el assert isNotNull

https://www.javadoc.io/doc/org.assertj/assertj-cor
e/latest/org/assertj/core/api/AbstractIterableAsse
rt.html#isNotNull

50
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

Si a parte queremos comprobar el contenido de


la petición que nos devuelve podemos hacer uso
de RestTemplate que realizará peticiones HTTP
por nosotros, veamos un ejemplo

51
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

import com.cursosdedesarrollo.aplicacionrest.controllers.MainRestController;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static
org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.web.servlet.MockMvc;

52
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?
@SpringBootTest
@AutoConfigureMockMvc
class AplicacionrestApplicationTests {
// Haciendo una Injección de Dependencias del Controlador en esta clase
// definir un atributo en la clase que se va a auto cargar
@Autowired
private MainRestController controller;
// prueba sobre el controlador
@Test
public void miRestControllerLoads() throws Exception {
// el controlador no es null, es decir carga correctamente
assertNotNull(controller);
assertThat(controller).isNotNull();
}
// Cargar el gestor de peticiones a la aplicación Web
// hace una especie de Mock que carga la aplicación y hace peticioens
@Autowired
private MockMvc mockMvc;

@Test
public void shouldReturnHello() throws Exception {
// realizar una petición
this.mockMvc.perform(
// hacer un método get en la petición
// indicando la ruta de acceso
get("/hello"))
// imprimir por pantalla el resultado
.andDo(print())
// comprobamos que el status es 200 OK
.andExpect(status().isOk())
// comprobamos que el contenido es lo que esperamos
.andExpect(content().string(containsString("Hello")));
}
}

53
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

Para por fin en el @Test realizar la petición


HTTP y la comprobación del contenido de la
respuesta de tipo String mediante el
getForObject

54
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

Dentro del Fichero de pruebas debemos incluir


la pnueva prueba para el Controlador que hemos
definido

55
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

Para esto en la clase de pruebas debemos


incluir el @AutoConfigureMockMvc delante de
la clase que queremos montar

56
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

Deberíamos crear una propiedad llamada


mockMvc del Tipo MockMvc que nos permita
realizar las llamadas inicializada con
@Autowired

57
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

Entonces realizaremos la petición get a la ruta


indicada, verificamos el status y verificamos el
contenido

58
Spring Avanzado www.cursosdedesarrollo.com
3 Testing
¿Y cómo pruebo todo esto?

El Given de BDD sería la inicialización del


Controlador, el When, es cuando hacemos la
petición al Controlador y el Then cuando
comprobamos el contenido y el status

59
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Tenido más o menos claro cómo se definen los


controladores y las pruebas de los controladores
veamos ahora cómo se define un API Rest
Básico

60
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

El primer paso debería ser definir el tipo del dato


que queremos manejar en el API Rest, para ello
nos vamos a ayudar de Lombok para definirlo

https://projectlombok.org/

61
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class Dato {
private Long id;

private String cadena;

62
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Como vemos usamos dos anotaciones: @Data y


@NoArgsConstructor

63
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

El @Data antes de la definición de la clase nos


ayudará a no necesitar definir los getter y
setters, el toString , el equals, el hashCode y el
constructor con los parámetro requeridos

https://projectlombok.org/features/Data

64
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

El @NoArgsConstructor permite generar un


constructor sin parámetros

https://projectlombok.org/features/constructor

65
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Ahora crearemos la clase que nos permitirá


agrupar las funcionalidades de un Controlador
API Rest

66
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

import org.springframework.web.bind.annotation.*;
import java.util.LinkedList;
import java.util.List;

@RestController
@RequestMapping(value = "/api/dato")
public class APIController {

public List<Dato> listado = new LinkedList<>();


public Long lastID = 0L;
@GetMapping
public List<Dato> index(){
return this.listado;
}
}

67
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

En la definición de la clase podemos ver cómo


se configura el listado de datos en memoria y la
ruta principal gracias al @RequestMapping

68
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Además en el método index definimos el valor


que queremos devolver un listado de Dato que
viene el atributo que hemos definido
anteriormente

69
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Este listado de datos lo devolveremos en un


formato de JSON sobre una petición a la ruta
principal mediante el método get debido al
@GetMapping

70
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Veamos ahora el método que permite Añadir un


Dato a través del API Rest

71
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

@PostMapping
public Dato addDato(@RequestBody Dato dato) {
lastID++;
dato.setId(lastID);
this.listado.add(dato);
return dato;
}

72
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Definimos el método de entrada al Controlador


mediante la anotación @PostMapping

73
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Colocamos el dato que queremos que nos pasen


dentro del body de la petición Http mediante la
anotación @RequestBody en el argumento del
método

74
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Y también definimos el Dato a devolver en


formato JSON como lo que devuelve el método

75
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Veamos ahora el ejemplo de cómo pasar un


parámetro por URL para el ID del objeto a
obtener

76
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

@GetMapping("/{id}")
public Dato showDatoById(@PathVariable("id") Long id){
Dato d = this.listado.stream().filter(dato ->
dato.getId().equals(id)).findFirst().orElse(null);
System.out.println(d);
return d;
}

77
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Como vemos en el @GetMapping podemos


pasar la subruta al método que se sumará a la
predefinida en el @RequestMapping de la clase,
por lo que la ruta sería /api/dato/{id}

78
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

De esta manera identificamos el nombre del


parámetro a pasar y que recogeremos en la
anotación @PathVariable que tiene como único
parámetro de momento el nombre del parámetro
pasado por la URL

79
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Con ese dato conseguimos el dato y lo


devolvemos como parámetro devuelto por el
método en formato JSON

80
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Seguimos con la operación de update que


recoge el id por URL y el dato por el Body de la
petición

81
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

@PutMapping(value = "/{id}")
public Dato editDatoById(
@PathVariable("id") Long id,
@RequestBody Dato dato) {
Dato d = this.listado.stream().filter(elemento ->
elemento.getId().equals(id)).findFirst().orElse(null);
if (dato!=null){
int index = this.listado.indexOf(d);
dato.setId(id);
this.listado.set(index, dato);
return dato;
}else{
return new Dato();
}
}

82
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

En el caso del ID se comporta de manera similar


al read by ID ya que coge el ID de la URL con la
@PathVariable y el dato del body con el
@RequestBody

83
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Por lo demás devuelve el Dato modificado en


formato JSON devolviendo el objeto mediante el
return del método

84
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Por último tendremos el método que elimina un


objeto por su ID

85
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

@DeleteMapping(value = "/{id}")
public Dato deleteDatoById(@PathVariable Long id){
Dato d = this.listado.stream().filter(elemento ->
elemento.getId().equals(id)).findFirst().orElse(null);
if (d !=null){
this.listado.remove(d);
return d;
}else{
return new Dato();
}
}

86
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

Como vemos disponemos de un único parámetro


a capturar por la URL mediante el
@PathVariable y que habíamos metido
previamente en el @DeleteMapping

87
Spring Avanzado www.cursosdedesarrollo.com
4 API Rest
¿Cómo defino un API Rest Básico?

En este caso devolvemos el Dato como siempre


con el return del método del controlador

88
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

Ahora es cuando debemos realizar las pruebas


sobre el API Rest que acabamos de programar

89
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

Empezamos creando la clase de pruebas

90
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.util.ArrayList;
import java.util.List;
import static
org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest

class ApiControllerTest {
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper mapper;

public String basePath = "/api/v1/dato";

91
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

Como hemos visto tenemos que meter la


anotación @WebMvcTest para que arranque la
aplicación cuando lance las pruebas

92
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

Para poder interactuar contra el api podemos


usar el componente MockMvc que lo
inicializamos con el @Autowired

93
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

De cara a manejar los objetos en JSON


podemos usara el ObjectMapper inicializado con
el @Autowired

94
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

Definimos también el basePath para facilitar la


creación de la url de consulta en todos los
métodos por si cambia

95
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

De cara a empezar siempre por un sistema


limpio antes de cada pruebas deberemos limpiar
la “base de datos”

96
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

Para ello deberemos crear un nuevo método en


el controlador base que nos permita realizar esta
labor

97
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

// ApiController.java
@GetMapping("/clear")
List<Dato> clear(){
this.listado = new LinkedList<>();
this.lastID = 0L;
return this.listado;
}

98
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

Ahora usaremos el @BeforeEach para que llame


a ese método antes de la ejecución de cada
pruebas

99
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

// ApiControllerTest.java
@BeforeEach
public void clearRestData() throws Exception {
System.out.println("limpiando");
mockMvc.perform(
MockMvcRequestBuilders
.get("/api/dato/clear")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}

100
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

A partir de ese momento ya podemos empezar a


escribir las pruebas empezando por el listado de
datos

101
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

@Test
void testListShouldReturnOkResult() throws Exception {
mockMvc.perform(
MockMvcRequestBuilders
.get(basePath+"/")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
}

102
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

En este caso realizamos la llamada vía get a


baseUrl+”/” y comprobamos que nos devuelve
código 200

103
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

Podemos meter una prueba que verifique el


contenido que nos devuelve

104
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

@Test
void testListShouldReturnOkResult() throws Exception {
List<Dato> listadoEsperado= new ArrayList<Dato>();
mockMvc.perform(
MockMvcRequestBuilders
.get(basePath+"/")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
// comprobación del tipo de contenido
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
// comprobación del contenido
.andExpect(content().json(mapper.writeValueAsString(listadoEsperado)));
}

105
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

En este caso veremos el tipo de contenido así


como el contenido que nos devuelve

106
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

Después podemos mirar a ver cómo gestionar


una petición post para añadir un dato

107
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

@Test
void testAddShouldReturnDato() throws Exception {
mockMvc.perform(
MockMvcRequestBuilders
.post(basePath+"/")
.content(asJsonString(new Dato(0L,"valor")))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().json(mapper.writeValueAsString(new
Dato(1L,"valor"))));
}

108
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

Para enviar los datos será necesario crear el


string para enviar los datos JSON mediante una
función

109
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

public static String asJsonString(final Object obj) {


try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

110
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

Ahora deberíamos comprobar si podemos


consultar los datos con su id pasado como
parámetro de URL

111
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

@Test
void testGetByIDShouldReturnDato() throws Exception {
// metemos el dato antes de consultarlo
testAddShouldReturnDato();
mockMvc.perform(
MockMvcRequestBuilders
.get(basePath+"/1")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().json(mapper.writeValueAsString(new
Dato(1L,"valor"))));
}

112
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

Después probaremos el Update de un elemento


en el que tendremos que enviar el ID por URL y
el dato vía JSON y el método Put

113
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

@Test
void testUpdateShouldReturnDato() throws Exception {
// metemos el dato antes de consultarlo
testAddShouldReturnDato();
mockMvc.perform(
MockMvcRequestBuilders
.patch(basePath+"/1")
.content(asJsonString(new Dato(0L,"valor1")))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().json(mapper.writeValueAsString(new
Dato(1L,"valor1"))));
}

114
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

Por último probamos el borrado pasando el


parámetro ID por URL y pasando el método
Delete

115
Spring Avanzado www.cursosdedesarrollo.com
5 Testing Rest
¿Cómo pruebo un API Rest Básico?

@Test
void testRemoveByIDShouldReturnDato() throws Exception {
// metemos el dato antes de consultarlo
testAddShouldReturnDato();
mockMvc.perform(
MockMvcRequestBuilders
.delete(basePath+"/1")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().json(mapper.writeValueAsString(new
Dato(1L,"valor"))));
}

116
Spring Avanzado www.cursosdedesarrollo.com
6 ResponseEntity
¿Y si no es un código 200?

Pero no sólo de códigos 200 podemos vivir en


los API’s Rest, también deberemos manejar
otros códigos diferentes HTTP

117
Spring Avanzado www.cursosdedesarrollo.com
6 ResponseEntity
¿Y si no es un código 200?

Para ello usaremos una clase de Spring llamada


ResponseEntity

118
Spring Avanzado www.cursosdedesarrollo.com
6 ResponseEntity
¿Y si no es un código 200?

Esta clase permite la construcción de una


respuesta completa incluyendo el código HTTP
de salida

119
Spring Avanzado www.cursosdedesarrollo.com
6 ResponseEntity
¿Y si no es un código 200?

Esta clase es genérica por lo que deberemos


indicar el Dato que queremos devolver con la
salida

120
Spring Avanzado www.cursosdedesarrollo.com
6 ResponseEntity
¿Y si no es un código 200?

Por ejemplo nuestro método que nos devuelve


un objeto por su ID quedaría así

121
Spring Avanzado www.cursosdedesarrollo.com
6 ResponseEntity
¿Y si no es un código 200?

// importaciones
import org.springframework.http.ResponseEntity;

// dentro de la clase
@GetMapping("/{id}")
public ResponseEntity<Dato> showDatoById(@PathVariable("id") Long id){
Dato d = this.listado.stream().filter(dato ->
dato.getId().equals(id)).findFirst().orElse(null);
System.out.println(d);
ResponseEntity<Dato> datoResponseEntity = null;
if (d!=null){
datoResponseEntity = ResponseEntity.ok(d);
}else{
datoResponseEntity = ResponseEntity.notFound().build();
}
return datoResponseEntity;
}

122
Spring Avanzado www.cursosdedesarrollo.com
6 ResponseEntity
¿Y si no es un código 200?

Lo primero será generar la referencia al objeto

ResponseEntity<Dato> datoResponseEntity

Y disponer del objeto a introducir

Dato d

123
Spring Avanzado www.cursosdedesarrollo.com
6 ResponseEntity
¿Y si no es un código 200?

Y generaremos una salida con ese dato y un


código 200:

ResponseEntity.ok(d)

124
Spring Avanzado www.cursosdedesarrollo.com
7 Testing ResponseEntity
¿Y cómo probamos esas salidas?

En el caso de las pruebas que realizamos será


necesario probar las nuevas salidas que
estamos generando

125
Spring Avanzado www.cursosdedesarrollo.com
7 Testing ResponseEntity
¿Y cómo probamos esas salidas?

Para ello deberemos añadir nuevos casos de


prueba que incluyan la posibilidad de generar
estas salidas y comprobar esos nuevos códigos

126
Spring Avanzado www.cursosdedesarrollo.com
7 Testing ResponseEntity
¿Y cómo probamos esas salidas?

@Test
public void testRemoveByIDShouldNotReturnDato() throws
Exception {
mockMvc.perform(
MockMvcRequestBuilders
.delete(BASEURL+"1")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().is(404));
}

127
Spring Avanzado www.cursosdedesarrollo.com
7 Testing ResponseEntity
¿Y cómo probamos esas salidas?

Como se puede ver podemos comprobar


cualquier estado gracias al método is de status()

128
Spring Avanzado www.cursosdedesarrollo.com
8 ControllerAdvice
¿No podemos ordenarlo mejor?

Esta generación en base a ResponseEntity está


muy bien pero nos obliga a escribir mucho
código de generación de posibles errores

129
Spring Avanzado www.cursosdedesarrollo.com
8 ControllerAdvice
¿No podemos ordenarlo mejor?

Para ello Spring ofrece la posibilidad de


gestionar los errores como excepciones
manejadas con una clase con la anotación
@ControllerAdvice

130
Spring Avanzado www.cursosdedesarrollo.com
8 ControllerAdvice
¿No podemos ordenarlo mejor?

Esta clase manejará las excepciones generadas


desde los controladores capturando sus
excepciones y asociando métodos para su
manejo y que permitan devolver

131
Spring Avanzado www.cursosdedesarrollo.com
8 ControllerAdvice
¿No podemos ordenarlo mejor?
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import java.util.Date;

@ControllerAdvice
public class ControllerExceptionHandler {
@ExceptionHandler(value = {ResourceNotFoundException.class})
public ResponseEntity<ErrorMessage>
resourceNotFoundException(ResourceNotFoundException ex, WebRequest
request) {
ErrorMessage message = new ErrorMessage(
200,
new Date(),
ex.getMessage(),
"Error capturado por ResourceNotFoundEcxeption");
return new ResponseEntity<ErrorMessage>(message,
HttpStatus.NOT_FOUND);
}
}

132
Spring Avanzado www.cursosdedesarrollo.com
8 ControllerAdvice
¿No podemos ordenarlo mejor?

Como vemos la clase tiene definido un método


que devuelve un
ResponseEntity<ErrorMessage>

133
Spring Avanzado www.cursosdedesarrollo.com
8 ControllerAdvice
¿No podemos ordenarlo mejor?

ErrorMessage es una clase que generamos para


incluir los datos que necesitemos devolver

134
Spring Avanzado www.cursosdedesarrollo.com
8 ControllerAdvice
¿No podemos ordenarlo mejor?

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.Date;

@Data
@AllArgsConstructor
public class ErrorMessage {
private int statusCode;
private Date timestamp;
private String message;
private String description;
}

135
Spring Avanzado www.cursosdedesarrollo.com
8 ControllerAdvice
¿No podemos ordenarlo mejor?

El método que recibe la excepción pilla como


parámetros la excepción que la ha generado así
como la petición Web recibida

ResourceNotFoundException ex y
WebRequest request

136
Spring Avanzado www.cursosdedesarrollo.com
8 ControllerAdvice
¿No podemos ordenarlo mejor?

Generamos el objeto del mensaje que queremos


devolver y lo metemos dentro de un objeto de
tipo ResponseEntity

137
Spring Avanzado www.cursosdedesarrollo.com
8 ControllerAdvice
¿No podemos ordenarlo mejor?

Para generar la excepción deberemos modificar


los métodos del RestController para incluir la
generación de la excepción si es necesario

138
Spring Avanzado www.cursosdedesarrollo.com
8 ControllerAdvice
¿No podemos ordenarlo mejor?

// importaciones
import org.springframework.data.rest.webmvc.ResourceNotFoundException;

// dentro del controlador


@GetMapping("/{id}")
public ResponseEntity<Dato> showDatoById(@PathVariable("id") Long id){
Dato d = this.listado.stream().filter(dato -> dato.getId().equals(id)).findFirst()
.orElseThrow(() -> new ResourceNotFoundException("Not found with id
= " + id));
System.out.println(d);
return ResponseEntity.ok(d);

139
Spring Avanzado www.cursosdedesarrollo.com
8 ControllerAdvice
¿No podemos ordenarlo mejor?

Como vemos en vez de devolver un null con el


orElse lo que hacemos es generar la excepción
el con .orElseThrow donde pasamos una lambda
que genera la excepción

140
Spring Avanzado www.cursosdedesarrollo.com
8 ControllerAdvice
¿No podemos ordenarlo mejor?

Así el código queda muchísimo más limpio

141
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

Hemos visto cómo gestionar el API Rest pero no


cómo documentarlo para lo cual vamos a usar el
están dar de OpenApi

https://www.openapis.org/

142
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

Este estándar heredero de Swagger nos va a


permitir documentar el proyecto mediante este
estándar

https://swagger.io/

143
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

Para ello vamos a utilizar una biblioteca que se


integra con Spring Boot para llamada springdoc-
openapi v2

https://springdoc.org/v2/

144
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

Necesitamos usar la versión 2 de esta biblioteca


para Spring Boot 3+ si fuera para Spring Boot 1
y 2 usaríamos la versión 1

https://springdoc.org/

145
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

En nuestro caso usaremos la siguiente


dependencia en el pom.xml

<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.2</version>
</dependency>

146
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

Para evitar un fallo de una inicialización de las


validaciones deberemos incluir la dependencia
en el pom.xml

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.0.Final</version>
</dependency>

147
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

SpringDoc se encargará se buscar las


definiciones de las rutas de nuestro Api Rest en
nuestra aplicación gracias a las anotaciones de
los controladores

148
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

149
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

Si todo ha funcionado bien deberíamos de poder


entrar en la URL:

http://localhost:8080/swagger-ui/index.html

150
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

Para configurar los datos principales de la


documentación usaremos delante de la clase de
la aplicación:

@OpenAPIDefinition(
info = @Info(
title = "Dato API", ok
version = "2.0",
description = "Dato API Demo")
)

151
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

Para configurar los datos principales de la


documentación usaremos delante de la clase de
la aplicación:

@OpenAPIDefinition(
info = @Info(
title = "Dato API", ok
version = "2.0",
description = "Dato API Demo")
)

152
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

Para definir un tag o agrupación de rutas


podemos meter delante de la clase controladora:

@Tag(
name = "dato",
description = "the dato simple API"
)

153
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

Cuando queramos documentar a mano un


método o ruta podemos incluir tanto los datos de
definición de entrada como de salida de la ruta
definida antes del método que lo manejo

154
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

@Operation(
summary = "show list of dato objects",
description = "Shows a list of dato in an output array",
tags = { "dato" }
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "Successful operation",
content = {
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Dato.class)),
@Content(
mediaType = "application/xml",
schema = @Schema(implementation = Dato.class)) })
})

155
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

De cara a definir los datos de entrada


deberemos usar el @Parameter por ejemplo en
el addDato:

@PostMapping(consumes = { "application/json",
"application/xml", "application/x-www-form-urlencoded" })
public Dato addDato(
@Parameter(description = "Created user object")
@Valid @RequestBody Dato dato) {
}

156
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

O también podemos definir diferentes salidas


para una misma ruta

157
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

@Operation(summary = "Show dato", description = "Shows a dato


object by ID", tags = { "dato" })
@ApiResponses(value = {
@ApiResponse(responseCode = "404", description = "Dato
not found"),
@ApiResponse(
responseCode = "200",
description = "Successful operation",
content = {
@Content(
mediaType = "application/json",
schema = @Schema(implementation =
Dato.class)),
@Content(mediaType = "application/xml",
schema = @Schema(implementation =
Dato.class))
}),
})

158
Spring Avanzado www.cursosdedesarrollo.com
9 Swagger OpenApi
¿Cómo lo documentamos?

Con todos estos datos codificados como


anotaciones podemos hacer la documentación
de manera muy completa

159
Spring Avanzado www.cursosdedesarrollo.com
10 HATEOAS
¿Y si lo ponemos fácil?

HATEOAS es principio de Arquitectura Rest en el


que el cliente interactúa con tu aplicación que
provee de hipervínculos que indican donde
consultar la información asociada

https://en.wikipedia.org/wiki/HATEOAS

160
Spring Avanzado www.cursosdedesarrollo.com
10 HATEOAS
¿Y si lo ponemos fácil?

Es decir a parte de la información propia de la


entidad que manejamos podemos dar enlaces
en un atributo _links o links del objeto que
devolvemos

161
Spring Avanzado www.cursosdedesarrollo.com
10 HATEOAS
¿Y si lo ponemos fácil?

Para manejar este estándar Spring incorpora un


nuevo framework que se puede integrar con
Spring y Spring Boot: Spring Hateoas

https://docs.spring.io/spring-hateoas/docs/curren
t/reference/html/#preface

162
Spring Avanzado www.cursosdedesarrollo.com
10 HATEOAS
¿Y si lo ponemos fácil?

Como siempre deberemos incluir la dependencia


de Spring Hateoas en el fichero pom.xml

163
Spring Avanzado www.cursosdedesarrollo.com
10 HATEOAS
¿Y si lo ponemos fácil?

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>

164
Spring Avanzado www.cursosdedesarrollo.com
10 HATEOAS
¿Y si lo ponemos fácil?

Con este biblioteca podremos crear enlaces con


la clase Link

import org.springframework.hateoas.Link;

165
Spring Avanzado www.cursosdedesarrollo.com
10 HATEOAS
¿Y si lo ponemos fácil?

Si queremos que nuestro DTO sea capaz de


manejar estos enlaces deberemos hacer
modificaciones en la clase del DTO para que
herede de RepresentationModel<MiDTO>

166
Spring Avanzado www.cursosdedesarrollo.com
10 HATEOAS
¿Y si lo ponemos fácil?

import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.hateoas.RepresentationModel;

@EqualsAndHashCode(callSuper = true)
@Data
public class Customer extends
RepresentationModel<Customer> {
private Long customerId;
private String customerName;
private String companyName;
}

167
Spring Avanzado www.cursosdedesarrollo.com
10 HATEOAS
¿Y si lo ponemos fácil?

A partir de ese momento podemos añadir los


enlaces al objeto antes de devolverlo veamos un
ejemplo en el controlador

168
Spring Avanzado www.cursosdedesarrollo.com
10 HATEOAS
¿Y si lo ponemos fácil?

import static
org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;

@PostMapping
public ResponseEntity<Customer> add(@RequestBody Customer
customer){
lastID++;
customer.setCustomerId(lastID);
this.listado.add(customer);
Link link =
linkTo(CustomerApiController.class).slash(lastID).withSelfRel();
customer.add(link);
return ResponseEntity.ok(customer);
}

169
Spring Avanzado www.cursosdedesarrollo.com
10 HATEOAS
¿Y si lo ponemos fácil?

Que nos debería devolver un objeto con las


siguientes características

170
Spring Avanzado www.cursosdedesarrollo.com
10 HATEOAS
¿Y si lo ponemos fácil?

{
"customerId": 1,
"customerName": "David",
"companyName": "CursosDeDesarrollo",
"_links": {
"self": {
"href": "http://localhost:8080/api/customer/1"
}
}
}

171
Spring Avanzado www.cursosdedesarrollo.com
10 HATEOAS
¿Y si lo ponemos fácil?

En el objeto que nos devuelve nos da la URL


donde podemos adquirir el objeto que hemos
creado

172
Spring Avanzado www.cursosdedesarrollo.com
6 Conclusiones
¿Qué podemos sacar en claro?

• Hemos visto cómo generar un proyecto Spring


Boot Rest
• Hemos visto cómo manejar los controladores
de Rest
• Hemos visto cómo incluir parámetros en URL
• Hemos visto cómo devolver datos en formato
JSON
• Hemos visto cómo gestionar el estado devuelto
con la respuesta

173
Spring Avanzado www.cursosdedesarrollo.com
CURSOS DE DESARROLLO
DAVID VAQUERO
LICENCIA CC-BY-SA-NC 4.0
[email protected]
https://creativecommons.org/licenses/by-nc-sa/4.0/
http://cursosdedesarrollo.com

También podría gustarte