How to validate Request Headers [String, Integer and Boolean] @RequestBody @RequestHeader Spring Boot - Full example
- Obtener vínculo
- X
- Correo electrónico
- Otras apps
Bienvenidos a esta nueva entrada del blog.
Veremos como validar un String, Integer y un Boolean en el Request o el Header que se declaran en un @RequestHeader o @RequestBody de un Microservicio REST con Spring Boot.
Para nuestro ejemplo manejaremos una identidad o model en nuestro @RequestBody que contendrá lo siguiente:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.spring.remote.model; | |
import javax.validation.constraints.Min; | |
import javax.validation.constraints.NotEmpty; | |
import javax.validation.constraints.NotNull; | |
public class RequestBodyModel { | |
@NotEmpty | |
private String name; | |
@NotNull | |
@Min(1) | |
private Integer age; | |
@NotNull | |
private Boolean active; | |
public Boolean getActive() { | |
return active; | |
} | |
public void setActive(Boolean active) { | |
this.active = active; | |
} | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public Integer getAge() { | |
return age; | |
} | |
public void setAge(Integer age) { | |
this.age = age; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.spring.remote.controllers; | |
import javax.validation.Valid; | |
import org.springframework.http.HttpHeaders; | |
import org.springframework.http.HttpStatus; | |
import org.springframework.http.ResponseEntity; | |
import org.springframework.web.bind.annotation.GetMapping; | |
import org.springframework.web.bind.annotation.RequestBody; | |
import org.springframework.web.bind.annotation.RequestHeader; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
import org.springframework.web.bind.annotation.RestController; | |
import com.spring.remote.model.RequestBodyModel; | |
@RestController | |
@RequestMapping("/data") | |
public class ValidController { | |
@GetMapping("/person") | |
public ResponseEntity<Object> getData( | |
@RequestHeader(required = true) Integer idType, | |
@RequestHeader(required = true) String identify, | |
@Valid@RequestBody(required = true) RequestBodyModel request | |
){ | |
return new ResponseEntity<Object>("Everything is OK", new HttpHeaders(), HttpStatus.OK); | |
} | |
} |
Si todo sale bien nos regresará un mensaje diciendo que todo esta bien.
Al armar un request desde Postman quedaría de la siguiente manera
Pero si le ingresamos tipos de datos que no son los correspondientes con los esperados por el @RequestHeader o el modelo del @RequestBody ??
Si le cambio el tipo de dato en el request de Postman al atributo age y envío la petición pasa lo siguiente
Nos salta un error que no se puede parsear al tipo de dato correspondiente.
En nuestro caso ya tenemos preparado una respuesta genérica para informar a quien nos consume, sobre el problema que esta sucediendo.
Nuestra clase que arma el response para informar del error es la siguiente
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.spring.remote.exceptions; | |
import java.sql.SQLException; | |
import java.util.Arrays; | |
import java.util.Set; | |
import javax.validation.ConstraintViolation; | |
import javax.validation.ConstraintViolationException; | |
import javax.validation.ElementKind; | |
import org.springframework.http.HttpStatus; | |
import org.springframework.http.ResponseEntity; | |
import org.springframework.http.converter.HttpMessageNotReadableException; | |
import org.springframework.web.HttpMediaTypeNotSupportedException; | |
import org.springframework.web.HttpRequestMethodNotSupportedException; | |
import org.springframework.web.bind.MethodArgumentNotValidException; | |
import org.springframework.web.bind.MissingRequestHeaderException; | |
import org.springframework.web.bind.annotation.ControllerAdvice; | |
import org.springframework.web.bind.annotation.ExceptionHandler; | |
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; | |
import org.springframework.web.servlet.NoHandlerFoundException; | |
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver; | |
import org.springframework.web.servlet.tags.form.ErrorsTag; | |
import com.spring.remote.model.ApiError; | |
@ControllerAdvice | |
public class RestException extends ExceptionHandlerExceptionResolver{ | |
//cuando el tipo HTTP no es correcto | |
@ExceptionHandler({HttpRequestMethodNotSupportedException.class}) | |
public ResponseEntity<ApiError> methodNotSupportedException(HttpRequestMethodNotSupportedException ex){ | |
ApiError error = new ApiError(); | |
error.setMensaje("HTTP " + ex.getMethod() + " NO soportado. Debe ser " +ex.getSupportedMethods()[0] + " para el endpoint solicitado"); | |
error.setDetalles(Arrays.asList(""+ex)); | |
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error); | |
} | |
//cuando el tipo de datos enviado no es aceptado | |
@ExceptionHandler({ HttpMediaTypeNotSupportedException.class }) | |
public ResponseEntity<ApiError> notAcceptableMediaTypeHandler(HttpMediaTypeNotSupportedException ex) { | |
ApiError error = new ApiError(); | |
error.setMensaje(ex.getMessage()); | |
error.setDetalles(Arrays.asList(""+ex)); | |
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error); | |
} | |
//cuando no existe el header requerido | |
@ExceptionHandler({ MissingRequestHeaderException.class }) | |
public ResponseEntity<ApiError> MissingRequestHeaderException(MissingRequestHeaderException ex) { | |
ApiError error = new ApiError(); | |
error.setMensaje("No existe " + ex.getParameter().getParameterName() + " en el header"); | |
error.setDetalles(Arrays.asList(""+ex)); | |
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error); | |
} | |
//cuando el body no es correcto | |
@ExceptionHandler(HttpMessageNotReadableException.class) | |
public ResponseEntity<ApiError> handleAllOtherErrors(HttpMessageNotReadableException ex) { | |
ApiError error = new ApiError(); | |
error.setMensaje(ex.getMessage()); | |
error.setDetalles(Arrays.asList(""+ex)); | |
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error); | |
} | |
//cuando @Valid tiene errores en validacion del body | |
@ExceptionHandler(MethodArgumentNotValidException.class) | |
public ResponseEntity<ApiError> MethodArgumentNotValidException(MethodArgumentNotValidException ex) { | |
ApiError error = new ApiError(); | |
error.setMensaje(ex.getMessage()); | |
error.setDetalles(Arrays.asList(""+ex)); | |
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error); | |
} | |
//cuando valores del body estan vacios o no existen | |
@ExceptionHandler(ConstraintViolationException.class) | |
public ResponseEntity<ApiError> ConstraintViolationException(ConstraintViolationException ex) { | |
ApiError error = new ApiError(); | |
error.setMensaje("Body no valido. Validar datos"); | |
ex.getConstraintViolations().stream().forEach(v -> { | |
v.getPropertyPath().forEach(e ->{ | |
if(e.getKind() == ElementKind.PROPERTY) | |
error.addDetalle(e.getName()+ " debe existir y no estar vacio"); | |
}); | |
}); | |
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error); | |
} | |
//cuando el tipo de dato del header no coincide | |
@ExceptionHandler(MethodArgumentTypeMismatchException.class) | |
public ResponseEntity<ApiError> MethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException ex) { | |
ApiError error = new ApiError(); | |
error.setMensaje("El header " + ex.getName() + " debe der de tipo " + ex.getRequiredType()); | |
error.setDetalles(Arrays.asList(""+ex)); | |
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error); | |
} | |
//cuando el path no existe | |
@ExceptionHandler(NoHandlerFoundException.class) | |
public ResponseEntity<ApiError> noHandlerFoundException(NoHandlerFoundException ex) { | |
ApiError error = new ApiError(); | |
error.setMensaje("Ruta " + ex.getRequestURL() + " no existe"); | |
error.setDetalles(Arrays.asList(""+ex)); | |
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error); | |
} | |
//cuando hay un error SQL | |
@ExceptionHandler(SQLException.class) | |
public ResponseEntity<ApiError> exception(SQLException ex){ | |
ApiError error = new ApiError(); | |
error.setMensaje(ex.getMessage()); | |
error.setDetalles(Arrays.asList(""+ex)); | |
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error); | |
} | |
} |
Pero que pasa si yo en el campo del Boolean active le pongo un numero (7)?, o en el caso del Integer age le pongo un decimal (34.6).
Vamos a ver como se comporta nuestro microservicio al cambiarle esos datos en el request del Postman.
Para el caso de la propiedad age para transparente
Para el caso del Boolean le ponemos un número
Están pasando transparente a nuestra validación.
Yo no puedo tener una edad decimal, o un boolean con un valor 3.
Entonces vamos a validar esos casos. Lo haremos desde el modelo, que es donde parte el API para parsear a los tipos correspondientes.
Validamos el atributo age, que no reciba decimales
El metodo setAge quedaría así
Ya no se nos esta escapando.
Ahora validaremos el Boolean active usando la misma estrategia del Integer
Nuestro setActive quedaría así
Y ahora si, nos valida
Si queremos validar también el String name, que no le pasen una cadena "true" o "false", podemos validarlo en el model.
Esto va a depender de las políticas de la empresa.
Para el caso de los headers lo podemos hacer usando la misma estrategia como lo hicimos con el body.
Esto sería todo de mi parte. Espero les sea de utilidad.
Cualquier duda pueden dejar su comentario.
Les dejo el link de descarga del proyecto completo.
- Obtener vínculo
- X
- Correo electrónico
- Otras apps
Comentarios
Best Casinos in San Francisco, CA - Mapyro
ResponderBorrarThe cheapest way to get from 영천 출장샵 San Francisco to Alton City Casino 포항 출장샵 & Hotel costs 의정부 출장마사지 only $3, 전라남도 출장안마 and the quickest way takes 안동 출장마사지 just 4 mins. Find the travel option that