I am using Apache HttpClient and would like to communicate HTTP errors (400 Bad Request, 404 Not Found, 500 Server Error, etc.) via the Java exception mechanism to the calling code. Is there an exception in the Java standard library or in a widely used library that would be appropriate to use or to subclass for this purpose?
The alternative is to check status return codes. This appears to be the HttpClient design philosophy, but since these errors are truly exceptional in my app, I would like to have the stack trace and other nice exception things set up for me when they happen.
If it's not an Exception in HttpClient design philosophy, but an Exception in your code, then create your own Exception classes. ( As a subclass of org.apache.commons.httpclient.HttpException )
Quick answer
In Spring you have exactly what you want:
HttpClientErrorException - Exception thrown when an HTTP 4xx is received.
HttpServerErrorException - Exception thrown when an HTTP 5xx is received.
And a recommended practice
Minimally, you should differentiate exceptions related to business logic (e.g., insufficient balance, email address is not valid) from other exceptions (e.g., server not available, unsupported media type, SQLException).
In our REST API, we have a library for Java clients that parses responses and throws only three different exceptions:
400, 401, 403, 404, 409, 422: throw MyBusinessException, which contains a message that can be shown to the end user. The message comes in the response body (exception handling on the service side), but if not present we have a default message specific to each status code.
405, 412, 415: throw HttpClientErrorException with a message that is specific to each status code.
other 4xx codes: throw HttpClientErrorException with a generic message.
5xx codes: throw HttpServerErrorException with a generic message.
All these exceptions are unchecked.
Check out the page on Exception Handling for HttpClient
To answer your question though there appears to be an org.apache.commons.httpclient.HttpException class that is probably a good fit.
If you do need a custom exception class for this I would think java.io.IOException would be the correct super class to use.
I'd say this depends on what you are using the HTTPClient for. For example, the PayPal SDK uses HttpClient to transmit API calls to the PayPal server, but fails to check the HTTP response code when it's done. I patched my copy so that if the response code isn't 200 it throws a PayPal FatalException, with an appropriate message. That's because the caller isn't interested in the HTML or any of the details of this HTTP post, and isn't even interested in the fact that we're using HTTP as a transport. If the call is successful then the body of the response contains transaction details, which are extracted and placed into a response object; otherwise it contains HTML which is useless. HTTP is just the transport in this case, so certain response codes indicate errors which can be reported using exceptions. Because this is part of the PayPal SDK, I used a PayPal Exception class. In some other system or library, I'd use a subtype of whatever exceptions that library already uses. For example, if I were writing a GMail library, which accesses GMail accounts, I'd probably create a GMailException class, and subclass that for the different kinds of exceptions the library runs into. Alternatively, you can use something like IOException.
The reason HttpClient makes you check response codes is because the response may be useful even if the response code is not 200. Some websites put useful text on a 404 page, either providing something useful for the user to do, or a search form, or just a helpful error message. Depending on your use case you may want to just show the response content rather than throw an exception.
I found this exception on Apache HTTP Client 4.5.7:
...
import org.apache.http.client.HttpResponseException;
...
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() != 200) {
throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
}
...
The sample of result is:
Exception in thread "main" org.apache.http.client.HttpResponseException: status code: 400, reason phrase: Bad Request
There is org.apache.commons.httpclient.HttpException if you want a library exception. We have also sometimes created our own for specific purposes, both creating an exception for specific HTTP status codes and a generic one for and unexpected status code.
Related
I have a REST service which is a POST to create a user, if the user does not exist, the user is created, and the service returns a 200 with the user in a json format.
Case 1: What if the user exists already, do I return a functionnal exception, so a json containing an error (all of this managed by the error handling of spring boot), and what about the http status code
Some people say to send a 303 or a 409 ... many different answers, and what about the response body in that case?
Case 2: What if in the backend we have let say a rule on the name (like containing a space) which returns an error (space not allowed in a name), same questions, do i have to return a functionnal exception and what about the http status code in this case
Somehow I want the API consumer to know what kind of json structure to handle and i guess the http status code helps for that ?
It all depends on how one interprets the various http status codes and how user friendly do you want your HTTP payload responses to be. Below are few suggestions:
NEW USER CREATED : If its a new user and gets created successfully in the backend then you return http status code 201. This is a technical status code. You can also return a functional status in the response body mentioning "User created"
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/201
USER ALREADY EXISTS : If the user already exists, you should respond with http status code 200 with a response payload body mentioning a functional status "User already exists"
USER CREATION FAILED : If the new user rules are not satisfied at the backend service and it throws an error then the http status code of 400 can be used and functional status in response payload of "User creation failed, please conform to the user name rules" https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400
For an API Consumer to know everything about your API's, you may want to provide a API specification document. You may use open API spec(previously known as swagger) https://swagger.io/specification/
Somehow I want the API consumer to know what kind of json structure to handle and i guess the http status code helps for that ?
Not quite.
The HTTP status code is meta data in the transfer documents over a network domain. It communicates the overall semantics of the response (for instance, is the body of the message a representation of a resource, or a representation of an error? is this response cachable? and so on).
For unsafe requests in particular, cache invalidation is sensitive to "non-error status codes". The difference between 303 (non-error status code) and 409 (error status code) can be significant.
The Content-Type header gives you a mechanism to describe the kind (schema) of the message you are returning (ex: application/problem+json).
The way I think about it: the information for your bespoke consumer belongs in the message-body; we lift data from the message-body to the HTTP metadata so that general-purpose components can take advantage of that information (for example, by invalidating cache entries).
So we would normally start by defining the schema and semantics of the message body, and making sure that we have intelligent ways to communicate all of the things we want the caller to know. In other words, we are defining the documents that we pass to the client, and how to extract information from them.
Information that HTTP components need to know get copied from our bespoke document into the standardized forms (status code, headers).
Where things get complicated: the fact that something is an "error" in your domain, that doesn't necessarily mean that it should also be considered to be an "error" in the transfer of documents over a network domain.
A common case: we are using our API to navigate some work through a process; that process has a happy path, and also some exceptional paths that we normally try to avoid (accounts are overdrawn, items are out of stock, etc).
An HTTP request can move work from the happy path to an exception path and still be a "success" in the transfer of documents domain.
The easiest heuristic I know is to think about previously cached copies of responses by the same target URI. If those responses are still re-usable, then you are probably looking at a 4xx status code. If the responses should be invalidated, then you are probably looking at a 2xx or 3xx status code.
I have situation where request syntax and data is proper and the data received from database is not in expected format - its a case of response data issue - In this scenario what is the suitable http status code.
Thought to use 422 - Unprocessable entity - its more on request body validation - please suggest
Thanks
Probably Internal Server Error(500) as the error is occurring on the server end.
4XX is only for client-side errors.
I like to think in this way;
Can the client(or user) get rid of the problem by himself, like changing request params or syntax? Use 4XX codes
Isn't there anything he can do without contacting support service? Use 5XX codes
In your case I would still think about the scenario;
User is requesting with correct syntax
Data is proper
So why returned data is not in expected format? Then there is a problem while data is being written do DB like missing validations etc. or some bugs exist.
4xx Client Error
The 4xx class of status code is intended for cases in which the client seems to have erred.
So, 4xx codes should be used only for client side errors, in your case, you should use an 5xx error, the best option in your situation is 500
The server encountered an unexpected condition which prevented it from fulfilling the request.
You can see more HTTP Status Codes here
I am referring to this project on Github. So this is supposed to be a RESTful API for managing a movie rental service. I mean it technically "works" right now, but one of the things it will do is deliver the error messages directly to the client from the internal methods.
Take this code for example:
/*
GET films
*/
get("/films", (req, res) -> {
try {
String json_output = get_film_list();
return json_output;
} catch (Exception e) {
return "{\"error\":\"There was an error: " + e.toString().replace("\"","") + "\"}";
}
});
And we have the get_film_list() method:
public static String get_film_list() throws SQLException, URISyntaxException{
Connection connection = ConnectionPool.getDBCP2Connection();
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM films");
String output = "{\"films\":[";
int got_result = 0;
while (rs.next()) {
output += "{\"id\":\""+rs.getInt(1)+"\",\"name\":\""+rs.getString(2)+"\",\"type\":\""+rs.getInt(3)+"\"},";
got_result = 1;
}
rs.close();
stmt.close();
output = output.substring(0, output.length()-1) + "]}";
if (got_result == 1){
return output;
}else{
throw new SQLException("No films.");
}
}
So the errors are delivered to the user via the API. I found this pretty convenient for development. I knew that if the server response contains the error property then there was an error, and it supplies the error message. I have heard through code review that this is not the way to do this at all. I also suspect that perhaps you're supposed to give formal HTTP errors or something. But at the same time I figured I would want my api to always return nice JSON formatted strings.
When a user hasn't authenticated, they will see this:
{"error":"Please Authenticate."}
I created an error in the DB connection class, and the user would see this:
{"error":"There was an error: java.sql.SQLException: Cannot load JDBC
driver class 'org.postgresql.Drive'"}
So, my question comes down to, what is the proper way to return error messages to the users with a RESTful API. One of this sort which uses returns JSON data.
Thanks!
RESTful services are based on 2 things, the response code and the actual response itself.
Well, basically it boils down to what error you want to handle. This particular scenario means no data being found and you would find different ways of handling this scenario. Any other error conditions would be handled differently
The 2 approaches to handling this error are
Scenario 1:
Response Code: 200 OK
Response: {}
which means that there was no data for the request specified(more so the parameters supplied with the request)
Scenario 2:
Response Code: 404 Not Found
Response: {"error":"Error Message"}
but this could potentially be confusing to indicate that the service was not found. But this depends on how you've defined your RESTful API.
From what I understand, the above scenario is a mix of both, where it sends out a 200 OK, but at the same time an error message too which is not the way to do it.
Its best to read through the rules of REST and then come up with your API.
Also it might be worth documenting your API through SWAGGER or RAML which makes it meaningful to someone using the service without going through tons of code to understand it.
Since you're using http you should use the http status codes properly, for example the SQL exception would probably result in a response code of 500 Internal Server Error, but you shouldn't expose the actual stack trace or exception at least for two reasons
The api-user has no use of that error message, he can't act upon it or take any reasonable actions to fix it.
You're exposing the applications internals, this could provide someone with malicious intent with valuable information.
When it comes to actually displaying an error. Hopefully something that the user can have some sort of use of. You can pretty much do it in any manner you feel fits your api. The important thing is that the api is consistent.
I'd say that the body of the response you're giving now is okay, except for the fact that the actual message probably doesn't mean anything to the intended user when you just call toString() on an Exception, that information is intended for the developers and should probably be logged.
What you need to do is, translate the exceptions to usable error messages and use http status codes.
When creating a REST API on the top of the HTTP protocol, the HTTP status codes are the proper way to indicate the result of the operation. Along with the status code, you can return a message with more details about the error.
Find below the most common status codes of errors for situations when the client seems to have erred:
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
409 Conflict
422 Unprocessable Entity
Don't define your own status codes. Stick to the standards.
When returning a message, your HTTP response can be like:
HTTP/1.1 404 Not Found
Content-Type: application/json
{ "error" : "Resource not found with the requested identifier" }
I have a small REST-ful Java back-end that some clients written in C connect to. There is a certain POST method they call where they send some information, I save that to a database and respond with 200 OK, if all goes well. Basic structure shown below.
#POST
#Path("/mypath")
#Produces("text/html")
public Response processMessage(final String message, #Context final HttpServletRequest request) throws IOException {
.....
return Response.ok().build();
}
My issue is that on this response, I get the following error in the log:
javax.ws.rs.NotAllowedException: No resource method found for , return 405 with Allow header
I understand what this error means in circumstances when let's say you try to execute a GET on an endpoint that is supposed to be a POST, for example. I can't understand though why I would get this after my response goes out, and it clearly shows that the request type is empty.... so odd.
Some additional info - the code on the client side has been buggy with incorrect HTTP code... but what would have to be wrong on the client side to cause this kind of response? (I do not have access to the client side code).
Also, there is no client side code in my app, if you are wondering if there is some other code making a call out of my webapp.
Thanks for any ideas!
The issue is most likely on the client side, so without seeing that code it is difficult to offer more detailed information -- but my expectation would be that this is a result of your client attempting to do something like POST or PUT credentials, or something along that line.
Your only recourse is to enable verbose request logging, log the requests that are generating 405 errors, and report it to the client developers.
Worth noting, however, that any publicly-exposed APIs will generate piles of 405s and 404s because "hackers" will try to execute things like WordPress hacks and so on against any known URL.
I could not find an exact answer to my question (either google or here), so my apologies if this is a repeat that I missed:
I am writing a XML-RPC server using Apache's XML-RPC libraries (which I'm regretting a bit) in Java that needs to conform to a given specification. With authentication, the server generates an org.apache.xmlrpc.common.XmlRpcNotAuthorizedException. This is not the behaviour that is required. I would like to return an HTTP error 401 (not authenticated) and 403 (forbidden) instead. However, Apache keeps on throwing these exceptions and I cannot find a way around it.
For example response received after sending correct username/password:
HTTP/1.1 200 OK
Content-Length:362
Content-Type:text/xml
Server:Jetty(7.x.y-SNAPSHOT)
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
...correct response information here
</methodResponse>
...and wrong username and password:
HTTP/1.1 200 OK
Content-Length:252
Content-Type:text/xml
Server:Jetty(7.x.y-SNAPSHOT)
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
...xmlrpc exception here
<methodResponse>
I don't want "HTTP/1.1 200 OK", I want "HTTP/1.1 401 Unauthorized"
I was considering inheriting Apache's ReflectiveXmlRpcHandler (or something similar) and trying to intercept the exception, but I was wondering if someone else have found a better idea to this problem.
Any ideas?
That seems to be difficult. As stated in the XML-RPC Specification
Response format
Unless there's a lower-level error, always return 200 OK.
Bad Authentication Credentials is not a low-level error, it's just a particular use case.
But you can enable Exceptions on the client side (be aware of security issues) to handle this particular case
I would post code but it touches a few too many places and by the time I had it here, it was an essay...
What I did:
Created PropagatedHttpException extending RuntimeException. It just has one field, code, which is the HTTP error code.
Extend XmlRpcServletServer:
Override writeError to check if the error is a PropagatedHttpException and if it is,
throw it back out immediately.
Override execute(HttpServletRequest, HttpServletResponse) to catch
PropagatedHttpException and pass it on as a proper HTTP error.
Extend XmlRpcServlet:
Set a custom AuthenticationHandler which throws PropagatedHttpException for
specific HTTP error codes.
Override newXmlRpcServer to return the custom XmlRpcServletServer.
We already had a custom authentication handler when we started to figure out how this would work but in your case maybe it isn't needed and the writeError code could be adjusted to check for XmlRpcNotAuthorizedException. Actually I had no idea this exception existed until today...
The problem you'll have now is that from the client side, Apache XML-RPC doesn't check the error code it gets back and then tries to parse the XML response irrespective of the result.
Grooveek's answer is extremely disheartening to us as we want authentication to be hooked into the JRE's built-in authentication so that things like NTLM can work, but if it's going to return an HTTP 200 then it is impossible for this to ever work without breaking the spec.