How to handle a BindException thrown by #Valid annotation using a controller advice which extends ResponseEntityExceptionHandler? - java

I have a #NotNull validation for some fields in a POJO which represents my request params:
Endpoint:
public ResponseEntity<Void> initializeLaunchPost(#Valid OidcFlowInitRequest request) throws LtiValidationException {
Request Body
#RequiredArgsConstructor
#ToString
#Getter
public class OidcFlowInitRequest { //java record public record keyword
#NotNull
private final String iss;
#NotNull
private final String loginHint;
#NotNull
private final String targetLinkUri;
}
I'm performing a test to check the exception thrown:
#Test
void whenRequiredParamNotPassedReturnBadRequest() throws Exception {
MultiValueMap<String, String> wrongInitFlowRequestParams = new LinkedMultiValueMap<>(initFlowRequestParams);
wrongInitFlowRequestParams.remove("iss");
mockMvc.perform(post(OIDC_INIT_FLOW_ENDPOINT).contentType(MediaType.APPLICATION_FORM_URLENCODED).params(wrongInitFlowRequestParams))
.andExpect(status().isBadRequest()).andExpect(jsonPath("$.description", containsString("Mandatory request param")))
.andDo(print());
}
The problem is that the only way to execute my exception handler is overriding this method which is marked as deprecated and for removal:
#RestControllerAdvice
public class ControllerExceptionAdvice extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
String field = ex.getFieldError().getField();
LtiErrorResponse body = new LtiErrorResponse(HttpStatus.BAD_REQUEST.value(),
"Mandatory request param <" + field + "> not present");
return handleExceptionInternal(ex, body, headers, status, request);
}
}
According to some post the test should be throwing MethodArgumentNotValid but if I implement that method is not executed. In fact, my test prints this in the console:
Resolved Exception:
Type = org.springframework.validation.BindException
So what other alternative do I have? My current solution it's not future proved.

Related

Spring http request validation with anotations

I am trying to implement validation of incoming http request in spring boot app.
I was following these instructions:
https://www.yawintutor.com/how-to-validate-request-body-in-spring-boot/
but I don't get response like stated in article.
I am getting exception in my console though: DefaultHandlerExceptionResolver: ... DefaultMessageSourceResolvable: default message [must be a well-formed email address]]
Process is stopped based on set constraint (email formating, obviously), but I don't get http response messages, just Bad Request.
This is my controller:
#RestController
#Validated
#RequestMapping(path = "/user", produces = MediaType.APPLICATION_JSON_VALUE)
public class UserController {
#PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> createUser(#Valid #RequestBody User user) {
User createdUser = userService.createUser(user);
return ResponseEntity.ok(user);
}
}
And this is entity :
#Entity
#Builder
#Data
#NoArgsConstructor
#AllArgsConstructor
public class User {
#Email
private String email;
}
What am I missing?
First of all I'd like to mention that for me the provided link (https://www.yawintutor.com/how-to-validate-request-body-in-spring-boot/) didn't work somehow...
Now to your question. As I see it, in order to archive this you'd have to create a validator first and then you could continue with something line this (not your example but it should help):
#RequestMapping(value = "/validation", method = RequestMethod.POST)
public ResponseEntity<?> acceptData(#Valid #RequestBody Data data, Errors errors,
#RequestHeader(HttpHeaders.ACCEPT_LANGUAGE) String language) {
stringValueValidator.validate(language, data, errors);
if (errors.hasErrors()) {
return new ResponseEntity<>(createErrorString(errors), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(HttpStatus.OK);
}
Use #ControllerAdvice and create your own response Object for representing not valid arguments. Example below will return all not valid arguments with its messages.
#ControllerAdvice
public class ExceptionHandlerClass extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
List<String> validationList = ex.getBindingResult().getFieldErrors().stream().map(fieldError->fieldError.getDefaultMessage()).collect(Collectors.toList());
return new ResponseEntity<>(new ExceptionObject(false,validationList), status);
} }

Return response code as 400 when #notnull validation fails

I'm using javax and Hibernate implementation for validation of my request payload.
version - org.hibernate:hibernate-validator:5.4.1.final
Sample Pojo:
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
public class Customer implements Serializable{
#NotNull(message="name is null")
#Size(min = 1)
public String name;
#NotNull(message="country is null")
#Size(min = 1)
public String country;
}
Sample controller:
#RequestMapping(value = {"/customer"}, method = RequestMethod.POST)
#ResponseBody
public Customer doAdd(#RequestBody #Valid Customer inData){
//some logic
return outData
}
Sample input json:
{
"country":"canada"
}
Console Exception:
org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument at index 0 in method: ........ model.request.Customer,java.lang.String,java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse), with 1 error(s): [Field error in object 'Customer' on field 'name': rejected value [null]; codes [NotNull.Customer.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [Customer.name,name]; arguments []; default message [name]]; default message [name is null]]
Here when customer.name is null, i'm getting response code as 422(Unprocessable entity). But i want to return 400(BAD Request). How can i override the response code here? Any document reference would be appreciated.
note - i don't want to do these validation at controller's side, where can i can check and send the response code accordingly.
Like this one - How to return 400 http status code with #NotNull?
Update - issue was resolved -------
The issue is resolved for me. Thanks all for your response.
Let me explain what was causing this,
HttpRequest ----> #Valid on RequestBody ----> Javax validation on Request object-----> If any of the validation fails, **MethodArgumentNotValidException** exception is thrown.
It is the responsibility of the developer to catch this exception and throw corresponding http response code.
In my case, the exception handler was already there and it was catching this MethodArgumentNotValidException and returning HttpStatus.UNPROCESSABLE_ENTITY. Thats the reason i was seeing 422 error code.
Now i have changed the exception handler as below,
#ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResource>
handleMethodArgumentNotValidException(MethodArgumentNotValidException exception, HttpServletRequest request) {
List<FieldErrorResource> fieldErrorResources = new ArrayList<>();
BindingResult bindingResult = exception.getBindingResult();
for (FieldError constraintViolation : bindingResult.getFieldErrors()) {
fieldErrorResources.add(FieldErrorResource.builder()
.field(constraintViolation.getField())
.resource(request.getContextPath())
.message(constraintViolation.getDefaultMessage()).build());
}
return responseEntityFor(HttpStatus.BAD_REQUEST,
"The content you've sent contains " + bindingResult.getErrorCount() + " validation errors.", fieldErrorResources);
}
You should set BindingResult immediately after your Customer. Like:
#RequestMapping(value = {"/customer"}, method = RequestMethod.POST)
#ResponseBody
public Customer doAdd(#RequestBody #Valid Customer inData, BindingResult bindingResult){
//some logic
return outData
}
You can use RestControllerAdvice for the same
#RestControllerAdvice
public class ExceptionRestControllerAdvice {
#ExceptionHandler({ConstraintViolationException.class})
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
public ExceptionResponseMessage handleInvalidParameterException(RuntimeException ex) {
return sendResponse(HttpStatus.BAD_REQUEST, ex);
}
private ExceptionResponseMessage sendResponse(HttpStatus status, RuntimeException ex) {
return new ExceptionResponseMessage(Instant.now(), status.value(), status.getReasonPhrase(),
ex.getClass().toString(), ex.getMessage());
}
}
public class ExceptionResponseMessage {
private Instant time;
private int status;
private String error;
private String exception;
private String message;
// setter and getter and constructor

How to get error list by using BindingResult for #Valid List

I have a Spring controller method that I wanna validate using #Valid and get the BindingResult errorlist. But In my #RequestBody have List list.
#PostMapping(path="/save/inouts")
public ResponseEntity<List<InoutResponse>> saveInouts(#Valid InoutWrapper inouts, BindingResults res){
.....
}
class InoutWrapper {
private List<Inouts> inoutList;
//getters and //setters
}
So I need to get error list as well as each error has the reference to Inout object to make InoutResponse.
You have 2 options, either remove the #valid annotation from the controller parameter and call the validation explicitly. Like below:
javax.validation.Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
final Set<ConstraintViolation<InoutWrapper>> constraints = validator.validate(inouts);
Or write an exception handler for your controller. I would prefer this one. Something like below:
#ControllerAdvice
class MyExceptionHandler extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
// read ex.getBindingResult().
return super.handleMethodArgumentNotValid(ex, headers, status, request);
}
}

Custom error message containing parameter names when validation fails

I would like my API to return errorMessage when the request lacks of required parameters. For example let's say there is a method:
#GET
#Path("/{foo}")
public Response doSth(#PathParam("foo") String foo, #NotNull #QueryParam("bar") String bar, #NotNull #QueryParam("baz") String baz)
where #NotNull is from package javax.validation.constraints.
I wrote an exception mapper which looks like this:
#Provider
public class Mapper extends ExceptionMapper<ConstraintViolationException> {
#Override
public Response toResponse(ConstraintViolationException) {
Iterator<ConstraintViolation<?>> it= exception.getConstraintViolations().iterator();
StringBuilder sb = new StringBuilder();
while(it.hasNext()) {
ConstraintViolation<?> next = it.next();
sb.append(next.getPropertyPath().toString()).append(" is null");
}
// create errorMessage entity and return it with apropriate status
}
but next.getPropertyPath().toString() returns string in format method_name.arg_no, f.e. fooBar.arg1 is null
I'd like to receive output fooBar.baz is null or simply baz is null.
My solution was to include -parameters parameter for javac but to no avail.
Probably I could somehow achieve it with the use of filters:
public class Filter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
UriInfo uriInfo = requestContext.getUriInfo();
UriRoutingContext routingContext = (UriRoutingContext) uriInfo;
Throwable mappedThrowable = routingContext.getMappedThrowable();
if (mappedThrowable != null) {
Method resourceMethod = routingContext.getResourceMethod();
Parameter[] parameters = resourceMethod.getParameters();
// somehow transfer these parameters to exceptionMapper (?)
}
}
}
The only problem with the above idea is that ExeptionMapper is executed first, then the filter is executed. Also I have no idea how could I possibly transfer errorMessage between ExceptionMapper and Filter. Maybe there is another way?
You can inject ResourceInfo into the exception mapper to get the resource method.
#Provider
public class Mapper extends ExceptionMapper<ConstraintViolationException> {
#Context
private ResourceInfo resourceInfo;
#Override
public Response toResponse(ConstraintViolationException ex) {
Method resourceMethod = resourceInfo.getResourceMethod();
Parameter[] parameters = resourceMethod.getParameters();
}
}

How to respond with an HTTP 400 error in a Spring MVC #ResponseBody method returning String

I'm using Spring MVC for a simple JSON API, with #ResponseBody based approach like the following. (I already have a service layer producing JSON directly.)
#RequestMapping(value = "/matches/{matchId}", produces = "application/json")
#ResponseBody
public String match(#PathVariable String matchId) {
String json = matchService.getMatchJson(matchId);
if (json == null) {
// TODO: how to respond with e.g. 400 "bad request"?
}
return json;
}
In the given scenario, what is the simplest, cleanest way to respond with a HTTP 400 error?
I did come across approaches like:
return new ResponseEntity(HttpStatus.BAD_REQUEST);
...but I can't use it here since my method's return type is String, not ResponseEntity.
Change your return type to ResponseEntity<>, and then you can use the below for 400:
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
And for a correct request:
return new ResponseEntity<>(json,HttpStatus.OK);
After Spring 4.1 there are helper methods in ResponseEntity which could be used as:
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
and
return ResponseEntity.ok(json);
Something like this should work, but I'm not sure whether or not there is a simpler way:
#RequestMapping(value = "/matches/{matchId}", produces = "application/json")
#ResponseBody
public String match(#PathVariable String matchId, #RequestBody String body,
HttpServletRequest request, HttpServletResponse response) {
String json = matchService.getMatchJson(matchId);
if (json == null) {
response.setStatus( HttpServletResponse.SC_BAD_REQUEST );
}
return json;
}
It is not necessarily the most compact way of doing this, but quite clean in my opinion:
if(json == null) {
throw new BadThingException();
}
...
#ExceptionHandler(BadThingException.class)
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
public #ResponseBody MyError handleException(BadThingException e) {
return new MyError("That doesn’t work");
}
You can use #ResponseBody in the exception handler method if using Spring 3.1+, otherwise use a ModelAndView or something.
#ResponseBody does not work with #ExceptionHandler [SPR-6902] #11567
I would change the implementation slightly:
First, I create a UnknownMatchException:
#ResponseStatus(HttpStatus.NOT_FOUND)
public class UnknownMatchException extends RuntimeException {
public UnknownMatchException(String matchId) {
super("Unknown match: " + matchId);
}
}
Note the use of #ResponseStatus, which will be recognized by Spring's ResponseStatusExceptionResolver. If the exception is thrown, it will create a response with the corresponding response status. (I also took the liberty of changing the status code to 404 - Not Found which I find more appropriate for this use case, but you can stick to HttpStatus.BAD_REQUEST if you like.)
Next, I would change the MatchService to have the following signature:
interface MatchService {
public Match findMatch(String matchId);
}
Finally, I would update the controller and delegate to Spring's MappingJackson2HttpMessageConverter to handle the JSON serialization automatically (it is added by default if you add Jackson to the classpath and add either #EnableWebMvc or <mvc:annotation-driven /> to your config. See the reference documentation):
#RequestMapping(value = "/matches/{matchId}", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public Match match(#PathVariable String matchId) {
// Throws an UnknownMatchException if the matchId is not known
return matchService.findMatch(matchId);
}
Note, it is very common to separate the domain objects from the view objects or DTO objects. This can easily be achieved by adding a small DTO factory that returns the serializable JSON object:
#RequestMapping(value = "/matches/{matchId}", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public MatchDTO match(#PathVariable String matchId) {
Match match = matchService.findMatch(matchId);
return MatchDtoFactory.createDTO(match);
}
Here's a different approach. Create a custom Exception annotated with #ResponseStatus, like the following one.
#ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Not Found")
public class NotFoundException extends Exception {
public NotFoundException() {
}
}
And throw it when needed.
#RequestMapping(value = "/matches/{matchId}", produces = "application/json")
#ResponseBody
public String match(#PathVariable String matchId) {
String json = matchService.getMatchJson(matchId);
if (json == null) {
throw new NotFoundException();
}
return json;
}
The easiest way is to throw a ResponseStatusException:
#RequestMapping(value = "/matches/{matchId}", produces = "application/json")
#ResponseBody
public String match(#PathVariable String matchId, #RequestBody String body) {
String json = matchService.getMatchJson(matchId);
if (json == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
return json;
}
As mentioned in some answers, there is the ability to create an exception class for each HTTP status that you want to return. I don't like the idea of having to create a class per status for each project. Here is what I came up with instead.
Create a generic exception that accepts an HTTP status
Create an Controller Advice exception handler
Let's get to the code
package com.javaninja.cam.exception;
import org.springframework.http.HttpStatus;
/**
* The exception used to return a status and a message to the calling system.
* #author norrisshelton
*/
#SuppressWarnings("ClassWithoutNoArgConstructor")
public class ResourceException extends RuntimeException {
private HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
/**
* Gets the HTTP status code to be returned to the calling system.
* #return http status code. Defaults to HttpStatus.INTERNAL_SERVER_ERROR (500).
* #see HttpStatus
*/
public HttpStatus getHttpStatus() {
return httpStatus;
}
/**
* Constructs a new runtime exception with the specified HttpStatus code and detail message.
* The cause is not initialized, and may subsequently be initialized by a call to {#link #initCause}.
* #param httpStatus the http status. The detail message is saved for later retrieval by the {#link
* #getHttpStatus()} method.
* #param message the detail message. The detail message is saved for later retrieval by the {#link
* #getMessage()} method.
* #see HttpStatus
*/
public ResourceException(HttpStatus httpStatus, String message) {
super(message);
this.httpStatus = httpStatus;
}
}
Then I create a controller advice class
package com.javaninja.cam.spring;
import com.javaninja.cam.exception.ResourceException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
/**
* Exception handler advice class for all SpringMVC controllers.
* #author norrisshelton
* #see org.springframework.web.bind.annotation.ControllerAdvice
*/
#org.springframework.web.bind.annotation.ControllerAdvice
public class ControllerAdvice {
/**
* Handles ResourceExceptions for the SpringMVC controllers.
* #param e SpringMVC controller exception.
* #return http response entity
* #see ExceptionHandler
*/
#ExceptionHandler(ResourceException.class)
public ResponseEntity handleException(ResourceException e) {
return ResponseEntity.status(e.getHttpStatus()).body(e.getMessage());
}
}
To use it
throw new ResourceException(HttpStatus.BAD_REQUEST, "My message");
http://javaninja.net/2016/06/throwing-exceptions-messages-spring-mvc-controller/
I’m using this in my Spring Boot application:
#RequestMapping(value = "/matches/{matchId}", produces = "application/json")
#ResponseBody
public ResponseEntity<?> match(#PathVariable String matchId, #RequestBody String body,
HttpServletRequest request, HttpServletResponse response) {
Product p;
try {
p = service.getProduct(request.getProductId());
} catch(Exception ex) {
return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity(p, HttpStatus.OK);
}
With Spring Boot, I'm not entirely sure why this was necessary (I got the /error fallback even though #ResponseBody was defined on an #ExceptionHandler), but the following in itself did not work:
#ResponseBody
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ExceptionHandler(IllegalArgumentException.class)
public ErrorMessage handleIllegalArguments(HttpServletRequest httpServletRequest, IllegalArgumentException e) {
log.error("Illegal arguments received.", e);
ErrorMessage errorMessage = new ErrorMessage();
errorMessage.code = 400;
errorMessage.message = e.getMessage();
return errorMessage;
}
It still threw an exception, apparently because no producible media types were defined as a request attribute:
// AbstractMessageConverterMethodProcessor
#SuppressWarnings("unchecked")
protected <T> void writeWithMessageConverters(T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
Class<?> valueType = getReturnValueType(value, returnType);
Type declaredType = getGenericType(returnType);
HttpServletRequest request = inputMessage.getServletRequest();
List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);
if (value != null && producibleMediaTypes.isEmpty()) {
throw new IllegalArgumentException("No converter found for return value of type: " + valueType); // <-- throws
}
// ....
#SuppressWarnings("unchecked")
protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Class<?> valueClass, Type declaredType) {
Set<MediaType> mediaTypes = (Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
if (!CollectionUtils.isEmpty(mediaTypes)) {
return new ArrayList<MediaType>(mediaTypes);
So I added them.
#ResponseBody
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ExceptionHandler(IllegalArgumentException.class)
public ErrorMessage handleIllegalArguments(HttpServletRequest httpServletRequest, IllegalArgumentException e) {
Set<MediaType> mediaTypes = new HashSet<>();
mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
httpServletRequest.setAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
log.error("Illegal arguments received.", e);
ErrorMessage errorMessage = new ErrorMessage();
errorMessage.code = 400;
errorMessage.message = e.getMessage();
return errorMessage;
}
And this got me through to have a "supported compatible media type", but then it still didn't work, because my ErrorMessage was faulty:
public class ErrorMessage {
int code;
String message;
}
JacksonMapper did not handle it as "convertable", so I had to add getters/setters, and I also added #JsonProperty annotation
public class ErrorMessage {
#JsonProperty("code")
private int code;
#JsonProperty("message")
private String message;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Then I received my message as intended
{"code":400,"message":"An \"url\" parameter must be defined."}
Another approach is to use #ExceptionHandler with #ControllerAdvice to centralize all your handlers in the same class. If not, you must put the handler methods in every controller you want to manage an exception for.
Your handler class:
#ControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(MyBadRequestException.class)
public ResponseEntity<MyError> handleException(MyBadRequestException e) {
return ResponseEntity
.badRequest()
.body(new MyError(HttpStatus.BAD_REQUEST, e.getDescription()));
}
}
Your custom exception:
public class MyBadRequestException extends RuntimeException {
private String description;
public MyBadRequestException(String description) {
this.description = description;
}
public String getDescription() {
return this.description;
}
}
Now you can throw exceptions from any of your controllers, and you can define other handlers inside you advice class.
The simplest and cleanest way to handle exceptions in your controller without having to explicitly return ResponseEntity is to just add #ExceptionHandler methods.
Example snippet using Spring Boot 2.0.3.RELEASE:
// Prefer static import of HttpStatus constants as it's cleaner IMHO
// Handle with no content returned
#ExceptionHandler(IllegalArgumentException.class)
#ResponseStatus(BAD_REQUEST)
void onIllegalArgumentException() {}
// Return 404 when JdbcTemplate does not return a single row
#ExceptionHandler(IncorrectResultSizeDataAccessException.class)
#ResponseStatus(NOT_FOUND)
void onIncorrectResultSizeDataAccessException() {}
// Catch all handler with the exception as content
#ExceptionHandler(Exception.class)
#ResponseStatus(I_AM_A_TEAPOT)
#ResponseBody Exception onException(Exception e) {
return e;
}
As an aside:
If in all contexts/usages, matchService.getMatchJson(matchId) == null is invalid, then my suggestion would be to have getMatchJson throw an exception, e.g., IllegalArgumentException instead of returning null and let it bubble up to the controller's #ExceptionHandler.
If null is used to test other conditions then I would have a specific method, e.g., matchService.hasMatchJson(matchId). In general, I avoid null if possible in order to avoid an unexpected NullPointerException.
You also could just throw new HttpMessageNotReadableException("error description") to benefit from Spring's default error handling.
However, just as is the case with those default errors, no response body will be set.
I find these useful when rejecting requests that could reasonably only have been handcrafted, potentially indicating a malevolent intent, since they obscure the fact that the request was rejected based on a deeper, custom validation and its criteria.
Use a custom response with the status code.
Like this:
class Response<T>(
val timestamp: String = DateTimeFormatter
.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS")
.withZone(ZoneOffset.UTC)
.format(Instant.now()),
val code: Int = ResultCode.SUCCESS.code,
val message: String? = ResultCode.SUCCESS.message,
val status: HttpStatus = HttpStatus.OK,
val error: String? = "",
val token: String? = null,
val data: T? = null
) : : ResponseEntity<Response.CustomResponseBody>(status) {
data class CustomResponseBody(
val timestamp: String = DateTimeFormatter
.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS")
.withZone(ZoneOffset.UTC)
.format(Instant.now()),
val code: Int = ResultCode.SUCCESS.code,
val message: String? = ResultCode.SUCCESS.message,
val error: String? = "",
val token: String? = null,
val data: Any? = null
)
override fun getBody(): CustomResponseBody? = CustomResponseBody(timestamp, code, message, error, token, data)

Categories

Resources