Suppose I have REST endpoint which gives me properties of given media ID using GET. If user calls the endpoint with wrong HTTP verb, like POST or DELETE, I want to give descriptive error message saying "Method is not supported". I am using JAX-RS for REST mapping. JAX-RS just throws 404 with no descriptive error message.
What is the proper way of handling this scenario? Are there more descriptive ways of returning an error?
Related
I know sending a body with a GET request isn't the best idea but I'm trying to consume an existing API which requires it.
Sending a body with POST is straight-forward:
webClient.post()
.uri("/employees")
.body(Mono.just(empl), Employee.class)
.retrieve()
.bodyToMono(Employee.class);
It won't work with webClient.get() though, because while the post() method returns a WebClient.RequestBodyUriSpec, the get() method returns WebClient.RequestHeadersUriSpec<?>, which doesn't seem to allow any body definitions.
I've found a workaround for Spring RestTemplate here: RestTemplate get with body,
but had no luck finding any for the new WebClient.
While the other responses are correct that you shouldn't use a body with a GET request, that is not helpful when you do not own, or cannot change the already existing method you are calling.
The problems is WebClient#get returns a WebClient.RequestHeadersUriSpec which does not provide a way for us to set the body.
WebClient#post returns a WebClient.RequestBodyUriSpec which does provide us a way to set the body but will cause us to use the wrong HTTP method, POST instead of GET.
Thankfully for us stuck in this situation there is WebClient#method which returns a WebClient.RequestBodyUriSpec and allows us to set the HTTP method.
webClient.method(HttpMethod.GET)
.uri("/employees")
.body(Mono.just(empl), Employee.class)
.retrieve()
.bodyToMono(Employee.class);
You may still run into issues in your testing libraries though...
A GET reques has no body. It is forbidden (well, not forbidden, but not used at all) by the HTTP specification. You have two approaches here:
Do a POST. It is there just for that.
Use a query string and pass the data in that part of the URL.
Of course, you can attach the needed fields and pass a payload to the GET request, but it will probably be ignored, or worse, identified as an error and rejected by the server, before your served code has access to it. But if you are passing data to the server to do some processing with it, then POST is what you need to use.
Extracted from RFC-7231. HTTP 1.1. Semantics and code:
A payload within a GET request message has no defined semantics;
sending a payload body on a GET request might cause some existing
implementations to reject the request.
(markup is mine)
Reasons for this are, mainly, that a GET method must be idempotent, producing the same output for the same URL, if repeated. POST doesn't have these requirements, so POST is your friend.
I'm updating legacy code that uses the exchange method of Spring 3.1 Framework's RestTemplate class. I came across what appears to be a major omission of detail. When the rest client with which I am attempting to communicate returns a 400 status code, a HttpClientErrorException is thrown but there is no response body to provide detail as to why the server rejected the request. There looks like there is no way to retrieve the response body which would provide very helpful information.
I do not need to figure out what is wrong in my calling code as I have already done that. I just would like to know if there is some way I could access and log the body of the HTTP response if an error occurs on the call.
The response body is actually a property on HttpClientErrorException. It can be accessed via the following two accessors which it inherits from its parent class HttpStatusCodeException:
public byte[] getResponseBodyAsByteArray()
public String getResponseBodyAsString()
Cast your HttpClientErrorException e to HttpStatusCodeException:
((org.springframework.web.client.HttpStatusCodeException) e).getResponseBodyAsString()
I am working on developing RESTful service on Java using Spring framework. If exception occurs in my services layer i throw an exception bound to Http status code. For example when user's authentication fails i send response with 401 status code.
return new ResponseEntity<>(HttpStatus.valueOf(statusCode));
I would like to explain to RESTful service consumer what is wrong with his request sending not only the code but also textual explanation. I can do this either by adding custom message to response body or by replacing default response phrase. For example replace Unauthorized for 401 with User does not exist or Incorrect password.
The problem is HttpStatus from org.springframework.http is enum and error codes are bound to textual response phrases.
Can i somehow override those response phrases or i need another approach?
And is it good practice to replace default response phrase or it would be better to put explanation message to response body?
This should work:
First you can bound the request method to the type it produces by adding
produces = {MediaType.TEXT_PLAIN} to your #RequestMapping where MediaType is from import javax.ws.rs.core.MediaType this will produce text plain response.
Then you can return the following:
return new ResponseEntity<>(message, HttpStatus.UNAUTHORIZED); where message is the text message you want to show.
I want to understand how a RESTful web service identifies if a correct request method is called.
For example,
I have a REST service it exposes one operation which is of type GET.
Assume a REST client has invoked the operation using a wrong request method(PUT).
In this scenario, how the service/framework identifies a correct request method is invoked?
I have gone through various posts to understand the scenario but I don't find any information.
Please let me know your comments.
The first line sent in an HTTP request looks like this:
GET /index.html HTTP/1.1
The HTTP request thus contains the HTTP method (POST, PUT, GET, etc.). The framework reads this method, and invokes the Java method that is mapped (thanks to annotations, or XML configuration, or whatever) to the URL (also contained in the HTTP request, as shown above) and the HTTP method. If none is found, then an error response is sent back (405 Method Not Allowed, if the resource is found, but with another method, or 404 if the resource is not found).
It's the http protocol not REST that checks headers, and reports back with an error code.
REST is sort of a strategy, not an implementation.
Hope this helps.
I playing with my simple REST API prototype written in Spring 3.2 MVC / Tomcat 7.4 / PostgreSQL.
Now I am thinking what is the best way to solve these issues:
Somebody make a request to a resources that doesn't exist
Somebody make a request to a resource but is using unsupported HTTP method
Somebody make a request to a resource but provide incorrect or incomplete data
Issue 3 I can probably solve with checking data and response proper HTTP headers (HTTP 400 or HTTP 404 because data could not be found because some input data is missing), but I don't know how to solve (in Spring) issue 1 and 2.
What is the best practice for handling exceptions such these?
For issue 1 just return a 404 error.
Create a 404 exception:
#ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
}
Now throw that from any handler and the client will get a 404 error.
For issue 2 the framework will automatically generate and return an error page for you if you set up your filters correctly, or if not generate and send a 405 not allowed code.
For issue 3 return a 400 Bad Syntax error in the same way as for issue 1 - or generate a more complex error return detailing the problem.
Return 404 (Not found)
Return 405 (Method not allowed)
Return 400 (Bad Request)
A word of advice, the body/headers of 404 that you return when someone request a URL path that doesn't exist should be different than if a resource doesn't exist. This will allow your clients to figure out if they are calling the wrong url or if the resource doesn't exist.
For the case #1, it's a clear 404 Not Found.
For the case #2, it's 405 Method Not Allowed.
For the case #3, it's a 400 Bad Request.
See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html for the description of these cases and the reasoning behind it.