I'm using Jersey 2.19 to implement a REST API.
I enabled ServerProperties.BV_SEND_ERROR_IN_RESPONSE to transform ConstraintViolationException into validation errors. This is working. In addition to the response code I get some text in the response that looks like:
Parameter value must be 'true' or 'false' (path = MyResource.m_myParam, invalidValue = invalid).
I have also created a custom exception mapper to map ConstraintViolationExceptions to a particular HTTP response code of my choosing.
This is also working.
However, I note that the additional information is no longer present int he response. If I call getMessage on the exception it returns null.
How do I get access to the same information in my mapper?
Just call ConstraintViolationException.getConstraintViolations() which will return a Set<ConstraintViolation>. Take a look at the ConstraintViolation API to see all the information you have access to.
The particular message you are showings is a String built from information obtained through getMessage(), getPropertyPath(), and getInvalidValue() of the ConstraintViolation
Related
hey I have a function in lambda with spring cloud functions that takes a dataobject as a input param say (InputObj).
The lambda is triggered via an api gateway.
The problem is if I leave out some properties of the InputObj and send a request. I get a default value for those missing properties.
What I would need is something like a 400 bad request error to be thrown unless the user provide all properties of the InputObj.
how can i go about doing it.
I say the simplest way to do that is to:
Not have default values. What's the point of having them if you are saying they are not valid.
Have the getter for the property to throw an exception if such property was not set. This way it will fail during serialization resulting in bad HTTP response
I am writing a web application using Spring Boot that frequently updates data on the back end and returns the updated object to reflect the update on the front end.
The question I have is what to return from my methods if the update should fail for some reason.
I am currently returning the object as it was received should it fail but as it stands the state on the front end would not reflect the failure on the back end in the case that it occurs.
I want to return the object to update the state but doing so prevents me from returning a String or HttpStatus indicating a problem doesn't it? Returning the old object doesn't seem a good solution either.
You can throw an exception in this case of failure from your REST controller.
To handle this exception, Spring provides ResponseEntityExceptionHandler callback class with the help of which you can handle the thrown exception and set different headers in the response entity.
So on client-side, you can recognise that some failure is occurred on server side.
You can set HttpStatus as HttpStatus.INTERNAL_SERVER_ERROR and add more details in the body.
The question I have is what to return from my methods if the update should fail for some reason.
You first need to determine whether the error was caused by the client or by the server, then you can determine the most suitable status code to be returned, either in the 4xx or in the 5xx range. See this answer which may give you some insights.
Instead of returning the request request back in the response, you should return a payload that describes what the problem was. Consider, for example, the payload defined in the RFC 7807 along with the application/problem+json media type.
Finally, this answer may give you insights on how to map an exception to a HTTP status code in Spring:
You can map exceptions to responses by annotating an exception class with #ResponseStatus.
It also gives you the possibility to implement a HandlerExceptionResolver or extend one of the existing implementations, such as the AbstractHandlerExceptionResolver.
Another approach would be using a ResponseEntityExceptionHandler annotated with #ControllerAdvice and define the handled exceptions by annotating the implemented method with #ExceptionHandler.
Does Spring throw HttpRequestMethodNotSupportedException when a request body is not valid and #Valid (or #Validated) is used? I really expected MethodArgumentNotValidException.
Details: I have a small REST server built on Spring-Boot version 2.2.4. One of the methods looks like this:
#PostMapping("/yapp")
public Yapp kickYapp(#Validated #RequestBody YappDescriptor yappDescriptor) {
logger.debug("kickYapp descriptor {}", yappDescriptor);
doWork(yappDescriptor);
}
The YappDescriptor has annotations like "required" but nothing for valid values, ranges, etc. When I POST a well-formed JSON object with values for all the required fields as defined in the YappDescriptor POJO, the Spring controller method is found and invoked as expected.
I tried a couple error scenarios:
1) If I POST a well-formed JSON object that has only null values for the expected fields, the method is found and entered as expected.
2) If I POST a well-formed JSON object with a key that does not match any of the POJO's fields, the method is NOT found and entered. In watching class org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler I see the exception is HttpRequestMethodNotSupportedException and the server answers 405 "Request method 'POST' not supported".
In this controller class, kickYapp is the only POST-mapped method at the specified path, so I think that answer is pretty confusing. Altho I'm definitely sending a bad request (unexpected data), I am surprised my POST-mapped method is not found and invoked.
This post Validating if request body in HTTP POST request is null in Spring Boot controller suggests I should be seeing HttpMessageNotReadableException which would be helpful, but I never get that exception.
Many other questions on SO seem to be about enabling validation of request bodies, like Spring 4.1.7 validate request body , but I seem to be past that.
Thanks in advance for helping me understand this behavior and maybe improve the server to help my users discover their errors more easily (which saves me time :). Thought I could maybe extend that method to accept a BindingResult parameter and report errors that way, but that's a non-starter if the controller method is never entered.
Update to respond to comments: yes I could have used #Valid. In my tests annotation #javax.validation.Valid and #org.springframework.validation.annotation.Validated have the same effect, both turned on validation of the RequestBody parameter.
why not use #Valid?
like so:
public ResponseEntity<SalaryDto> update(#Valid #RequestBody SalaryDto subject)
and don't forget to use javax.validation validation annotations in your request body object
The JAX-RS implementation Jersey supports MVC style web applications through the Viewable class, which is a container for a template name and a model object. It is used like this:
#GET
#Template
#Produces({MediaType.TEXT_HTML})
public Viewable get() {
JsonObject response = null;
try{
response = service.getDetails(id);
}
catch(Exception ex) {
log.error("failed to get details", ex);
throw ex;
}
return new Viewable("/test", response);
}
this is right way to send the json from Viewable? Is there a way to set a json object explicitly?
A few things: I don't have any experience using Viewable in particular, but I am familiar with JAX-RS and can probably throw a couple of pointers your way.
Exception Handlers
JAX-RS defines a feature for mapping exceptions to responses. This functionality is nice for removing those exception blocks from your resource code. Check out the Jersey docs on this topic for a tutorial on how to register these. A quick summary is: 1) implement ExceptionMapper and 2) register the class as a Provider.
For starters, I recommend creating a simple suite that maps to common HTTP codes. For example:
NotFoundException - returns a 404 response and is used when a single entity is requested but not found.
InvalidInputException - returns a 422 response and is used when a request does not pass validation (like trying to save an phone number in an email field).
BadRequestException - usually the framework will handle these situations for you, but if not, a Bad Request is one that is not formatted properly. So if a required header is missing, or if a client tries to save a collection when only a single entity is allowed.
Exception* - There is a star here because an unexpected exception is usually due to a server error, so 500 is an appropriate default response. A reason you may want to create a global uncaught exception handler is to prevent the stacktrace from being returned in the response body. That can be bad for security reasons.
View and Model
You should not need the #Template annotation if you are using the Viewable object. Also, Viewable is expecting a template as the first argument and a model (map) as the second argument. The model should have keys that match variables in your JSP. Right now your method will look for a file called test.jsp in the root of whatever your template config is set to in web.xml. If you take all of that into consideration, your method could look something like this:
#GET
#Produces(MediaType.TEXT_HTML)
public Viewable getMobileReport() {
return new Viewable("/test", service.getMobileReport(id));
}
I am using Java and Jersey for my REST web services. I want to have a put method that takes just one integer value. From this integer value I can then use business logic to update my database. Usually I am passing a custom DTO from my PUT as they often contain more than one piece of information. It seems a bit wasteful creating a custom DTO for just one value. Is it possible to pass this variable as a #PathParam with a PUT
I have tried
#PUT
#Path("apple/{pearId}")
public void doStuff(#PathParam("pearId") Integer pearId) {...}
but this does not work if I pass in
http://myurl/apple/123
I tried using REST client to PUT this but end up with a HTTP Status 403
Can I pass a variable as a PUT #PathParam?
Thanks
UPDATE: more details on error
The error is from REST Client
HTTP Status 403 -
type Status report
message
descriptionAccess to the specified resource () has been forbidden
I will add logging now to see if I actually get into the method
You can definitely use #PathParam with a PUT. HTTP 403 means Forbidden. This error is probably not coming from Jersey. Where is that error coming from? Does your code throw that error?