How exactly works the #ResponseStatus Spring annotation for RESTful application? - java

I am studying for the Spring Core certification and I have some doubts about how Spring handles REST requests.
I know that with REST the resources are exposed as name and that the actions on these resources are the HTTP methods, such as GET, PUT, POST, and DELETE.
And I know that requests are handled by the use of #RequestMapping annotations over the method that handles the operation on the resource.
From what I have understood, both standard web applications and RESTful applications use some codes to communicate with their clients (the RESTful application have an expanded set of codes) that I think represent the status of the request (for example 200 is the request is a successful GET returning content, etc.).
Now the documentation shows the use of the #ResponseStatus annotation as in this example:
#RequestMapping(value="/orders", method=RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED) // 201
public void createOrder(HttpServletRequest request, HttpServletResponse response) {
Order order = createOrder(request);
// determine full URI for newly created Order based on request
response.addHeader("Location",
getLocationForChildResource(request, order.getId()));
}
So looking at the previous method I know that it handles HttpRequest POST requests towards the resource named /orders (using REST the resource is seen as an URL, is that correct?).
But what exactly does the annotation below do:
#ResponseStatus(HttpStatus.CREATED) // 201
I know that the 201 status code means that a new resource was created on POST.
And looking at the official documentation I can read:
Marks a method or exception class with the status code and reason that
should be returned. The status code is applied to the HTTP response
when the handler method is invoked, or whenever said exception is
thrown.
So what exactly it means? I think that as is done in the previous example it sets the 201 status that says that the resource is correctly created by the POST request. If this is correct I have 2 questions:
The resource is the /orders URI. So what is created? a file named orders (I think that this assertion is false) or what?
Where the 201 status is put?

201 is an HTTP status code. It indicates that the
request has been fulfilled and resulted in a new resource being created.
So if your server is returning such a status code, then the client understands that some (conceptual) resource was created. What that resource is is your responsibility, you're the server.
A status code is part of the HTTP response status line.

Actually, the JavaDocs for the ResponseStatus annotation warn us not to use this annotation for REST APIs. This annotation will cause Spring to call the HttpServletResponse.sendError() method, which will result in an HTML Error page. You don't want that in a RESTful service. Here's what it says:
Warning: when using this annotation on an exception class, or when setting the reason attribute of this annotation, the HttpServletResponse.sendError method will be used.
With HttpServletResponse.sendError, the response is considered complete and should not be written to any further. Furthermore, the Servlet container will typically write an HTML error page therefore making the use of a reason unsuitable for REST APIs. For such cases it is preferable to use a ResponseEntity as a return type and avoid the use of #ResponseStatus altogether.

Related

How to debug 406 not acceptable error in java application using spring

My code is using spring boot and java but while testing a method it is showing 406 not acceptable error how to debug??
406 Not Acceptable
The resource identified by the request is only capable of generating
response entities which have content characteristics not acceptable
according to the accept headers sent in the request.
So, probably your request accept header is different then your controller's produce type (application/json, text/json etc). This happens when the correct HTTPMessageConverter can not be found to satisfy the #ResponseBody annotated return value.
Please provide your controller you are testing and test case

Is it possible to programmatically resolve producible content-type given a request in spring-webflux?

My application uses spring-webflux, it still uses classic #Controllers with #RequestMapping-annotated handler methods.
Some methods produce application/json, while others produce text/event-stream.
When a request hits a controller, there is no problem: each mapping has produces with the corresponding media type defined.
The application also uses spring-security (the reactive flavor). If an unauthenticated request arrives, we must build a error response using correct format: JSON for application/json endpoints and a Server-Sent-Event for text/event-stream endpoints.
The problem is that security checks are made before the request handler is resolved, so Spring has no clue about the correct response media type at this point.
If a client sends Accept header, this solves the problem: we just parse it and decide what content type to use, with something like the following:
request.getHeaders().getAccept().contains(MediaType.TEXT_EVENT_STREAM)
(the algorithm is oversimplified, but you get the idea).
But some clients do not send Accept header at all. Strictly speaking, we have all the information we need: we have request, and, somewhere in spring-webflux beans information about all the mappings is stored.
So the question is: how (only having ServerWebExchange instance and access to Spring context) do you make use of this mapping information to find out what media types are supported by a handler corresponding to the current request?
P.S. What I tried/thought of so far:
Manually maintain list of all streaming endpoints... yuck!
Use a bean post-processor to collect information about all mappings and then try to emulate spring-webflux behavior... cumbersome and probably fragile.

Spring boot REST server throws HttpRequestMethodNotSupportedException on POST of unexpected request body with #Validated

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

Best practices for method types in JAX-RS

What are the best practices regarding the method types in JAX-RS ?
I am interested in the following methods: GET, POST, PUT and DELETE.
My possible approaches:
GET - always return a response.
#GET
#Path("/path/{something}")
public T getT() {
...
return t; // t - instance of T
}
POST
#POST
#Path("/path")
public T/void createOrUpdate() {
...
return t; // t - instance of T
}
Q: Is it better to return the entire created resource or just an "ACK response" or to have a void method? What about a POST that is used as GET (when we want to avoid the URL length limitation)?
PUT
#PUT
#Path("/path")
public T/void createOrUpdate() {
...
return t; // t - instance of T
}
Q: Is it better to have a void method or a response for the created/updated resource or different responses for creation / update or just an ACK response ?
DELETE
#DELETE
#Path("/path/{something}")
public T/void deleteT() {
...
return t; // t - instance of T
}
Q: Is is better to have a void method or to return the deleted resource or to return an ACK response ?
Is it ok to always have T = javax.ws.rs.core.Response (when T is used)?
I saw that:
Lars Vogel uses GET - T, POST - void, PUT - T, DELETE - void
Oracle uses GET - T, POST - T/void, DELETE - void
JAX-RS is a specification for developing RESTful Web Services with Java. There is a reference implementation that is included in Java EE but since it is a specification, other frameworks can be written to implement the spec, and that includes Jersey, Resteasy, and others.
JAX-RS as such does not lay down any guidelines on the return types and response codes for the REST API's. However, there are a few guidelines (these are not hard and fast rules) in the REST standard which you might want to follow:
Method GET
Successful Response RETURN the resource with 200 OK
Failure Response RETURN appropriate response code
Method POST
Successful Response RETURN the link to the newly created resource in Location response header with 201 status code
Failure Response RETURN appropriate response code
Method PUT
Successful Response RETURN the updated resource representation with 200 OK or return nothing with 204 status code
Failure Response RETURN appropriate response code
Method DELETE
Successful Response RETURN nothing with 200 or 204 status code
Failure Response RETURN appropriate response code
In practice, POST works well for creating resources. The URL of the newly created resource should be returned in the Location response header. PUT should be used for updating a resource completely. Please understand that these are the best practices when designing a RESTful API. HTTP specification as such does not restrict using PUT/POST with a few restrictions for creating/updating resources. Take a look at Twitter REST API best practices that summarizes the best practices for RESTful API's.
This answer is not correct/up to date. Please check #ROMANIA_engineer answer instead.
You should never return void. The best practice is to always return a javax.ws.rs.core.Response. But note that even if you define the webresource with void, your server will return a HTTP response.
On POST and PUT, it may be better to return the modified resource, including its id. Some front-end framework and/or middleware will use it to synchronise the resource with your server (as instance, see Backbone Model).
On DELETE, it depends of the action you try to achieve.. But usually an ACK is enough.
NB : Anyway, whatever you return, don't forget to respect your security policies !
Response #Atul : When you send HTTP Request from client or HTTP Response from your server, some data may be protected. As instances :
On user update (username, password, or anything else) do not return the user password in the HTTP Response.
When user log in, you better use a HTTPS protocol and never send the password in plaintext
.. etc
I give it a shot and state a "no there is no best practice". This because the underlying protocol (HTTP) actually has return values (such as 200-OK, 500-Internal Error...) in any case unless a broken connection which should be followed by your service as well.
Since you are not implementing the HTTP-Protocol but a own-designed service following its own rules, no there is no best practice, you will have to define "your protocol" in a way it matches your day to day business the best.
For example when it comes to your delete operation a caller could either not be interested in a response at all or as well expect you to work like a stack and return him the "deleted/removed" element on call. It is up to you to know what fits your needs best.

Servlet include swallows HTTP headers in Tomcat

I have a servlet that does a request dispatcher include of another servlet.
The included servlet sets headers that I would like to read in the including servlet. So I pass in a custom HTTPResponse object in the include() method which captures all feedback activity from the servlet.
The problem is that the headers are not being set in my custom response. I've run in debug and examined what looks like Tomcat wrapping my custom response object with its own response object. The setHeader calls go to this wrapping class and never propagate to my custom response object.
I imagine Tomcat does this to protect the client from headers being set in the wrong place. The funny thing is that the same approach works the way I'd expect in Jetty.
It's been a while since I've done Servlets seriously so I'm struggling a bit here. I'm trying to figure out how to read the response headers from a servlet that's invoked via dispatcher.include().
From the Servlet specifications section SRV.8.3:
The include method of the RequestDispatcher interface may be called at any time.
The target servlet of the include method has access to all aspects of the request
object, but its use of the response object is more limited.
It can only write information to the ServletOutputStream or Writer of the
response object and commit a response by writing content past the end of the
response buffer, or by explicitly calling the flushBuffer method of the
ServletResponse interface.
It cannot set headers or call any method that affects
the headers of the response. Any attempt to do so must be ignored.
How about setting your values for the calling servlet in request scope, with request.setAttribute(...) and then reading it from there once you return? Could that work?

Categories