| Tabla de contenidos |
|---|
...
| Info | ||
|---|---|---|
| ||
Para ver cómo obtener tanto el token en los métodos REST, podemos verlo en la guía de login: Login con OAuth en Spring Boot |
| Advertencia | ||
|---|---|---|
| ||
Se deben documentar las APIs con OpenAPI, para lo que tenemos otra guía: Documentar APIs con OPENAPI |
Para la implementación de los servicios REST desde el backend Spring, se ha optado por usar las librerías nativas (Spring) incluidas ya que engloban todas las necesidades funcionales a la hora de crear servicios y/o clientes Spring integradas con el framework y con numerosas facilidades que reducen el tiempo de desarrollo.
Buenas prácticas
Para crear nuestros servicios REST debemos seguir las buenas prácticas que están definidas en esta página de la wiki: Buenas prácticas con servicios REST
Devolver ResponseEntity
En los métodos en los que devolvamos datos, devolveremos objetos tipo ResponseEntity. Este tipo nos da más flexibilidad, permitiendo modificar la respuesta HTTP entera, controlando el código que se devuelve, los headers y los datos del body.
Un ejemplo de uso sería el siguiente. Para crear unResponseEntityque devuelva un objetoUsuarioDTO, y códigoOK 200:
| Bloque de código | ||
|---|---|---|
| ||
@GetMapping(value = "/usuarios", params = "login")
public ResponseEntity<UsuarioDTO> usuariosLogin(@RequestParam login) {
// ...
return new ResponseEntity<>(usuarioDto, HttpStatus.OK);
} |
También podríamos mandar un400 Forbiddenasí:
| Bloque de código | ||
|---|---|---|
| ||
return new ResponseEntity<>(HttpStatus.FORBIDDEN); |
Controlador REST en Spring Boot
En Spring Boot, las peticiones HTTP se gestionan por medio de controladores. En nuestro caso la clase que hará de controlador REST deberá estar precedida por la anotación @RestController, y por @RequestMapping, que indicará la ruta base.
Para los métodos que contendrán el código a ejecutar al recibir peticiones disponemos de las etiquetasetiquetas @GetMapping, @PostMapping,@PutMappingy @PutMapping y @DeleteMapping, para los diferentes tipos de peticiones. En estas anotaciones pondremos la ruta a la que tendrá que hacerse cada petición. Por defecto, estas rutas irán después del dominio. Si queremos añadir una ruta base de la que partan todas las rutas de estos métodos podemos añadirlo en el archivoapplication.properties:
| Bloque de código |
|---|
server.servlet.context-path=/rest/v1.0 |
Veamos un ejemplo sencillo:
| Bloque de código | ||
|---|---|---|
| ||
package com.example.restservice; import java.util.concurrent.atomic.AtomicLong; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping( "${app.server.path}" ) public class GreetingController { private static final String template = "Hello, %s!"; private final AtomicLong counter = new AtomicLong(); @GetMapping("/greeting") public ResponseEntity<Greeting> greeting(@RequestParam(value = "name", defaultValue = "World") String name) { Greeting greeting = new Greeting(counter.incrementAndGet(), String.format(template, name)); return new ResponseEntity<>ResponseEntity.ok(greeting, HttpStatus.OK); } } |
Parámetros en la URL
@PathVariable
Para añadir parámetros en la ruta de la petición, tenemos dos opciones. En primer lugar, tenemostenemos PathVariable. Cuando especifiquemos la ruta, pondremos entre corchetes estas variables, y como parámetro del método Java lo especificaremos con el mismo nombre, precedido de la anotaciónanotación @PathVariable:
| Bloque de código | ||
|---|---|---|
| ||
@GetMapping("/titulaciones/{dni}")
public List<AlumnoTitulacionDTO> getTitulaciones(@PathVariable String dni) {
// ...
} |
Un ejemplo de petición quedaría así (suponiendo que tenemos la aplicación corriendo enen localhost:8080):
| Bloque de código |
|---|
http://localhost:8080/titulaciones/12312300A |
@RequestParam
La otra opción eses RequestParam, que funciona de manera similar, pero sólo se indica en los parámetros de la función Java. Si queremos que sea obligatorio incluir esa variable en la petición, pondremospondremos required = true:
| Bloque de código | ||
|---|---|---|
| ||
@GetMapping("/titulaciones")
public List<AlumnoTitulacionDTO> getTitulaciones(@RequestParam(required = true) String dni) {
// ...
} |
...
Estos parámetros irán después de ?, y si tenemos varios los separaremos con &.
Métodos REST con mismo nombre pero diferentes parámetros
Podemos definir diferentes métodos Java con la misma ruta de método REST, pero con diferentesdiferentes @RequestParam. Para ello, no nos vale sólo con tener diferentes argumentos, hay que indicarlos dentro de la anotaciónanotación @GetMapping, concon params, y tendremos que tener la ruta enen value:
| Bloque de código | ||
|---|---|---|
| ||
@GetMapping("/usuarios")
public List<UsuarioDTO> usuarios() {
// ...
}
@GetMapping(value = "/usuarios", params = "login")
public UsuarioDTO usuariosLogin(@RequestParam login) {
// ...
} |
De este modo podemos evitar tener métodos Java excesivamente largos por tener que comprobar diferentes parámetros y ejecutar el código correspondiente.
Headers de la petición: @RequestHeader
Para utilizar los valores de los headers de la petición, disponemos de la anotaciónanotación @RequestHeader. Dentro de ésta pondremos el nombre del header enen value, y podemos especificar si es obligatorio que se incluya dicho header concon required. Por ejemplo, podemos utilizarlo para obtener el token de autenticación:
| Bloque de código | ||
|---|---|---|
| ||
@GetMapping( "/dniAlumno" )
public ResponseEntity<String> dniAlumno( @RequestHeader( value = "auth-token", required = true ) String tokenCodificado ) {
final Claims claims = jwtTokenUtil.comprobarToken( tokenCodificado );
if(claims == null)
return null;
return new ResponseEntity<>ResponseEntity.ok(alumnoTitulacionRepository.findDni( claims.getSubject() ), HttpStatus.OK);
}
</java>
==== Datos en el body: @RequestBody ====
En caso de que hagamos un post, el cuerpo del mensaje se especificará con |
Datos en el body: @RequestBody
En caso de que hagamos un post, el cuerpo del mensaje se especificará con ''@RequestBody'':
| Bloque de código | ||
|---|---|---|
| ||
<code java> @PostMapping("/borrarUsuariocrearUsuario") public void borrarUsuariocrearUsuario(@RequestBody UsuarioDTO usuario) { usuarioRepo.deletecreate(new Usuario(usuario)); } |
...
La respuesta que se enviará a la petición, si la hay, será el objeto, con sus atributos y valores, automáticamente en formato JSON.
Devolver ResponseEntity o ResponseStatusException
En los métodos en los que devolvamos datos, si se devuelven los datos correctamente devolveremos objetos tipo ResponseEntity. Este tipo nos da más flexibilidad, permitiendo modificar la respuesta HTTP entera, controlando el código que se devuelve, los headers y los datos del body.
Un ejemplo de uso sería el siguiente. Para crear un ResponseEntity que devuelva un objeto UsuarioDTO, y código OK 200:
| Bloque de código | ||
|---|---|---|
| ||
@GetMapping(value = "/usuarios", params = "login")
public ResponseEntity<UsuarioDTO> usuariosLogin(@RequestParam login) {
// ...
return ResponseEntity.ok(usuarioDto);
} |
En el caso de que queramos devolver un error, por ejemplo, un Forbidden porque el usuario que ha solicitado un recurso no tiene acceso, lanzaremos una excepción ResponseStatusException, pues esta nos ofrece más información en la respuesta que se da.
| Bloque de código | ||
|---|---|---|
| ||
} catch (Exception e) {
throw new ResponseStatusException( HttpStatus.FORBIDDEN, "FORBIDDEN con ResponseStatusException", e);
} |
Devolver diferentes propiedades
La primera opción que tenemos para personalizar la respuesta es la anotación @JsonIgnore que le podemos poner a los getters. Con ella, esa propiedad directamente no se inclirá incluirá en el JSON de respuesta. Si lo que queremos es devolver propiedades según la ocasión, podemos hacer uso de las vistas.
...
Después, en el modelo, en el getter de cada propiedad que queramos mostrar con cada vista, debemos añadir la etiquetaetiqueta @JsonView(Views.Detalle.class), poniendo la clase correspondiente:
...
Más información sobre las Views aquí.
Cliente REST en Spring Boot
| Advertencia |
|---|
Este apartado queda obsoleto, se manendrá aquí temporalmente. |
| Expandir | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||||||||||||||||||||
Para consumir otro servicio REST desde el propio backend, a falta de realizar más pruebas, la forma que tendremos de hacerlo será utilizando
Después, en la clase en la que vayamos a utilizarlo, sólo tendremos que cargarlo con Autowired:
Para utilizarlo, formamos el URI con
Con Podemos añadir headers con
Los headers los incluiremos en un objeto
En el caso de que sólo queramos pasar los headers,
Para lanzar las peticiones tenemos diferentes opciones. En primer lugar, disponemos de cuatro métodos básicos para hacer GET, POST, PUT, DELETE:
Para las operaciones básicas estos métodos pueden ser útiles, pero como vemos, solo podemos pasar el objeto
Como vemos, estamos utilizando el tipo |