Handling 400 Bad Requests - java

When sending parameters as form data parameters instead of x-www-form-urlencoded parameters, my API returns an http 500 error.
I want the API to return http 400 bad request error along with a error number and appropriate error message.
My API method has #Consumes({ MediaType.APPLICATION_FORM_URLENCODED }) annotation
So I wrote an exception mapper to handle NotSupportedException.
But during the execution https://jersey.java.net/project-info/2.6/jersey/jersey-server/xref/org/glassfish/jersey/server/internal/routing/MethodSelectingRouter.html is called before my mapper and it throws NotSupportedException. But I want to customize the error shown to the user.

Related

Producing application/octet-stream and application/json

I have an endpoint that typically returns a document of type PDF, Word, etc. There is user input that goes along with this endpoint, however so I would like to validate it.
The trouble is, when I validate the input and want to return some sort of error JSON response, I end up getting errors similar to
Failed executing GET /foo/generateBar: NoMessageBodyWriterFoundFailure: Could not find MessageBodyWriter for response object of type: FooResponse of media type: application/octet-stream
What I am using on my endpoint is #Produces({"application/octet-stream", "application/json"})
Is there a way I can avoid this error by possibly returning both JSON and different file formats? My impression is that what the #Produces I was using was doing, however I'm probably thoroughly confused.
Additionally, I must note that I'm using window.open on the front-end side to call this endpoint.
In Java and in javax.ws.rs.core.Response, you should try something like this in you headers:
Response.status(response.getStatus())
.header("Accept", "application/json")
.header("Content-type", "application/json")
.entity(entity)
.build();
In order to solve this issue you have to consider the following aspects:
Exceptions mangement
Here you have to consider that each time you will have any exception you will throw custom exceptions and an exceptions handler will be implemented using #ControllerAdvice, or any other solution. This exceptions handler will return the response as a JSON.
Handling to return the application/octet-stream
To the endpoint, you need to mention that it will produce application/octet-stream. You can use: #GetMapping(produces = {MediaType.APPLICATION_OCTET_STREAM}).
Provide to the GET request, the proper headers
When you are calling the endpoint that produces the application/octet-stream you will add the Accept header with the value application/octet-stream, application/json. Now, in case of success, you'll receive the octet-stream and in case of any exception you'll receive the JSON response.
I hope this solution will help you!

ResponseBuilder is not working when used with entity object

I am trying to create a response with responsebuilder.
When I pass string in entity it works fine but when I pass some error class it doesnot works.
Here is code
1) Working fine
Response.status(400).entity("test").build();
2) Not working
Response.status(400).entity(new MyCustomExceptions(400,"My bad request")).build();
With above code I am getting error
org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor aroundWriteTo
SEVERE: MessageBodyWriter not found for media type=text/plain
when I call this service with above code I am getting 500 error instead of 400.But in 1st case I am getting proper 400 error.
Just wanted to understand if I pass object to entity then do I need
to override some methods in class MyCustomExceptions?
How response is created from MyCustomExceptions object?
If I pass string to entity it works fine.Why?
Mapping exceptions to HTTP error responses
JAX-RS allows you to define a direct mapping of Java exceptions to HTTP error responses.
By extending WebApplicationException, you can create application specific exceptions that build a HTTP response with the status code and an optional message as the body of the response.
With that in mind, instead of returning a Response, you could throw a BadRequestException which extends WebApplicationException and will be mapped to a HTTP response with the status code 400:
throw new BadRequestException("My bad request");
For more details regarding error handling in JAX-RS, refer to this answer.
Subclasses of WebApplicationException
For convenience, the WebApplicationException is currently extended by the following exceptions (and they can be extended to create your own exceptions):
RedirectionException: 3xx status codes for Redirection errors
ClientErrorException: 4xx status codes for Client errors
BadRequestException: 400 Bad Request
ForbiddenException: 403 Forbidden
NotAcceptableException: 406 Not Acceptable
NotAllowedException: 405 Method Not Allowed
NotAuthorizedException: 401 Unauthorized
NotFoundException: 404 Not Found
NotSupportedException: 415 Unsupported Media Type
ServerErrorException: 5xx status codes for Server errors
InternalServerErrorException: 500 Internal Server Error
ServiceUnavailableException: 503 Service Unavailable
What is the value of accept parameter in HTTPHeader that you're passing? Looks like its text/plain and you're trying to return an Object.
Pass the accept value as application/json in the request. OR
Change your code in response to add type as Json/XML
Response.status(400).type(MediaType.APPLICATION_JSON).entity(new MyCustomExceptions(400,"My bad request")).build();

How can i preserve the request headers in error response prepared through JAX-RS ( Apache-CXF implementation) ExceptionMapper

I am implementing JAX-RS using apache CXF. I have created an ExceptionMapper to handle bad requests like this:
public class ClientErrorExceptionMapper implements ExceptionMapper<ClientErrorException> {
#Override
public Response toResponse(final ClientErrorException exception) {
return Response.status(Response.Status.BAD_REQUEST).entity("Invalid request: Invalid URI.").build();
}
}
I am not sure how this works internally but i suppose that framework would throw an exception in case user is making an invalid request and this handler will prepare an error message to be send back. My problem is that i wish to preserve some custom headers that user sends in the request, so that i send that back with the response. But using this exception mapper, i cant see any option to get the original request headers. I can set any new header in the response, but i wish to preserve the request headers - like i do in a normal request.
So is there any way in JAX-RS where i can preserve or efficiently refer to the custom headers in current request ?
What we have resorted to is using a thread local variable to save the RequestContext when the request arrives and then in the ExceptionMapper we can obtain request specific information.
Ugly but it works. I think we have a generic filter in the filter list that catches all requests before dispatch.

ValidationError in Jersey Client?

I'm having trouble getting ValidationErrors from a jersey resource in jersey client. Let me explain.
A function in jersey resource:
#POST
#Produces({ MediaType.APPLICATION_JSON })
#Consumes(MediaType.APPLICATION_JSON)
public LoginInfo login(#NotNull #Valid Login login)
My clientconfig:
ClientConfig clientConfig = new ClientConfig();
clientConfig.register(JacksonFeature.class);
My jersey client:
ClientBuilder.newClient(getClientConfig())
And my function call:
getTarget("/login").request(MediaType.APPLICATION_JSON_TYPE).post(Entity.json(login), LoginInfo.class);
All works without problems as long i supply valid parameters, when i for example supply null as parameter i get exception:
HTTP 400 Bad Request
But i'm expecting a ValidationError response, because bean validation failed.
Bean validation and error response is working on server, for example with a simple html test, which shows validationerror structure:
<div class="validation-errors"><div class="validation-error"><span class="message">may not be null</span> (<span class="path"><strong>path</strong> = LoginResource.login.arg0</span>, <span class="invalid-value"><strong>invalidValue</strong> = null</span>)</div></div>
How do i get the ValidationError in my jersey client? Do i maybe have to configure it in a special way or maybe i should use a filter?
[edit]
I turned on tracing and when validation fails on server the server sends validationerrors, but it seems jersey client doesn't do anything with it, it converts it to BadRequestException.
6 < 400
6 < Content-Type: application/json
6 < Vary: Accept
[{"message":"may not be empty","messageTemplate":{org.hibernate.validator.constraints.NotBlank.message}","path":"RuleResource.add.arg0.description","invalidValue":""}]
Answering my own question ;-)
It seems jersey client doesn't support validationerrors, so i created a client filter and when status is 400 i get the entity and put the validation errors in a list. Next i create a validationexception which includes the validation errors and just throw it. A bit further up the chain i get a processingexception, in the stacktrace the validationexception can be found and also the validation errors. So i create a nice message from the validation errors and throw another exception, all the way up to my gui code which simply displays the exception message.
Works fine, thanks jersey for the flexibility of filters!

JAX-RS how to handle wrong content-type

I have a REST service with a #POST method which #Consumes("application/xml)".
However, if I make a POST request from my browser and I don't add
Content-Type: application/xml
header to the request, I get an exception in my jboss
Failed executing POST : org.jboss.resteasy.spi.UnsupportedMediaTypeException: Cannot consume content type
How is my servlet supposed to handle such cases?
You can implement an ExceptionMapper for the UnsupportedMediaTypeException and choose to handle it however you wish. You're seeing this exception because you don't have a handler for it and resteasy is doing its out of the box handling.

Categories