The title almost speaks for itself, but is valuable to always check isCommitted() on type ServletResponse? My particular example is in using a filter where I do the following if a user isn't authorized to perform a certain action (CSRF checks to be specific):
if (!httpResp.isCommitted()) {
httpResp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
In this case, it almost feels like overkill that I've checked the response. My filter is at the top of the chain, there should be nothing before it that would commit a response (let alone allow the filter chain to continue if it did), but I can't help but feel like this is an assumption which in the name of good defensive programming I shouldn't be making. I feel like it's good practice to check the status of the response.
So, all of that being said, is it valuable to check the response at this point in time? And to maybe extend this further, is it good practice to always check this every time a response is modified? In my case, I can hardly find reason to support something other than an exception being thrown when a CSRF token does not match (assuming that would only happen in an attack scenario).
In general, based on when some code is executed you know that the response has not been committed. I would not add this check everywhere.
Some places I would add it:-
a piece of library code that might be called in various different contexts
exception handling code that might be reached before or after the response has been comitted
Related
Normally I try to use exceptions only for "exceptional" conditions ("Effective Java ", Issue 69). My personal interpretation is:
if I hit a condition in a specific part in code (normally a method or constructor) where I can't give a meaningful answer or outcome anymore I throw an exception and whoever called the piece of code has to handle it.
In the special case of HTTP endpoints I can always give a meaningful answer - a response with a status code.
Handling bad requests thus belongs to normal program flow of endpoint methods and should not raise new exception.
E.g. an endpoint that returns a resource should just return 404 in case the resource is not found. In my opinion it would be bad practice to raise a "SomethingNotFoundExcetion" (that could be handled by an error handler and create 404 response)
My question is: It is bad practice to use Spring Boot's error handling mechanism for bad requests (4xy) that relies on exceptions to create specific HTTP responses. (It is really fine for all uncovered errors yielding 500)
(I am just writing a review of code and I am not sure if I should suggest to not use error handler for "normal" API interaction)
Answer/Comment to current answers
It seems that the most of you missed the important part of my reasoning:
(citing Effective Java, Item 69):
Use exceptions only for exceptional
conditions ...
this reasoning:
• Because exceptions are designed for exceptional circumstances, there is little
incentive for JVM implementors to make them as fast as explicit tests.
• Placing code inside a try-catch block inhibits certain optimizations that
JVM implementations might otherwise perform.
The main point for me is:
A well-designed API
must not force its clients to use exceptions for ordinary control flow.
Especially in case of rest API. It should be easy to use any API in a way to avoid exceptions at all. This means for me. No correct (defined e.g. in Open API) usage of a Rest API should raise an exception.
To put another point: The standard for SOAP (another http based API stuff) forbids to use "SOAP fault" for correct (defined by WSDL) requests.
For me raising exception in remote APIs on not exceptional cases are even worse then in classic API (via dependency).
It depends on your project, it's really a matter of opinion/architectural decision. I'd say either-or.
The advantage of using specific Exceptions and then using a Spring handler to map them is that it removes the tedious construction of responses with the correct code from the actual application logic code (it's not dissimilar from aspects in that respect): just throw the correct exception and be done with it.
OTOH, the distance to the error handling code means that 1. if something doesn't work, it may be difficult to track down the issue 2. you need to know what exceptions to throw, and that is not immediately obvious and needs to be documented well.
It is not a bad practice, but a matter of architectural decision. It could be good to have an error handler that will produce a 4xx response and will do some additional error handling work, such as logging, and/or sending a notification by mail or queue or (like in my project) write errors in the table so they could be reviewed by user using GUI component of an application and may be even edited and re-submitted if it makes sense. It also unifies the error handling to a single code (code re-use). But if you really just need to send a 4xx response and nothing else, then its OK not raise exception and just do it in your code. Raising exception is expensive performance-wise and shouldn't be done just for the sake of raising exception alone. But in this particular case my opinion is to use Exception/Spring boot Error handling mechanism
We have a REST API that reads and deletes the record from database and returns the read value back to the client, all in same call. We have exposed it using HTTP POST. Should this be exposed as HTTP GET? What will be the implications in terms of Caching in case we expose it as GET.
First, you should keep in mind that one of the reasons that we care that a request is safe or idempotent is that the network is unreliable. Some non zero number of responses to the query are going to be lost, and what do you want to do about that?
A protocol where the client uses GET to request the resource, and then DELETE to acknowledge receipt, may be a more reliable choice than burning the resource on a single response.
Should this be exposed as HTTP GET?
Perhaps. I would not be overly concerned with the fact that the the second GET returns a different response than the first. Safe/idempotent doesn't promise that the response will be the same every time, it just promises that the second request doesn't change the effects.
DELETE, for example, is idempotent, because deleting something twice is the same as deleting it once, even though you might return 200 to the first request and 404/410 to the second.
HTTP does not attempt to require the results of a GET to be safe. What it does is require that the semantics of the operation be safe, and therefore it is a fault of the implementation, not the interface or the user of that interface, if anything happens as a result that causes loss of property (money, BTW, is considered property for the
sake of this definition).
I think the thing to pay attention to here is "loss of property". What kind of damage does it cause if generic components think that GET means GET? and act accordingly (for example, by pre-fetching the resource, or by crawling the API).
But you definitely need to be thinking about the semantics -- are we reading the document, and the delete of the database record is a side effect? or are we deleting the record, and receiving a last known representation as the response?
POST, of course, is also fine -- POST can mean anything.
What will be the implications in terms of Caching in case we expose it as GET.
RFC 7234 - I don't believe there are any particularly unusual implications. You should be able to get the caching behavior you want by specifying the appropriate headers.
If I'm interpreting your use case correctly, then you may want to include a private directive, for example.
As per the above discussion, it looks like PUT request. You should not use GET as it is idempotent because the same data is not available for the second time call. POST is used to create a new resource. So it will be better to use PUT http method for this kind of requirement. Refer below the link for more details.
https://restfulapi.net/http-methods/
I am wondering what the correct way is to handle this type of request. I have a delete requests from a UI and it's a list of ID's which are integers. So the request can look like :
www.myui.com/delete/1,2,3,4
which is a well formatted request. But if the request for any reason came from a curl request or postman etc it may be formatted like:
www.myui.com/delete/1,,3,4
In this case the 2nd index will contain null since it's inspecting Integers. However if we were expecting a list of String it would be simple an empty string or an n amount of white space characters if it was formatted like /1, ,2,3, 4, so I would have to loop through the request and check if a string in the list of string is only white space and throw back a 404.
Should I be doing this in the controller or allow this type of request to pass on by and have the eventually have the exception thrown in the dao since it's going to try and delete an id that is either null or just white space which won't exist in the DB.
Below is an example of how I am currently handling the request which is a List of Integers.
#DeleteMapping(value="/delete/{ids}")
public ResponseEntity delete(#PathVariable("ids") List<Integer> ids)
throws DatabaseException {
if (ids.contains(null)) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
service.delete(ids);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
In short, fail fast is a better approach as it helps detect malfunctioning very early and quickly, although you might also consider business requirements and general design guidelines of your application, if it should be lenient, then you might go with something like:
service.delete(ids.stream().filter(Objects::nonNull).collect(Collectors.toList()));
and return a response body containing at least a number of items deleted.
If your application has to be strict, then a bad request should be returned as soon as possible as you are already doing.
Also, you have to take in consideration that your services and/or DAOs are not exclusively called from controllers, so validations and/or checks have to be implemented there as well, and try not to let malformed requests hit the database if you already know they would lead to errors, it would be just wasted traffic.
Finally, I hope the integer ids in your case are not DB generated, in which case it would be a major security issue since you are exposing persistence details over your api, an attacker could just wipe out your database or parts of it by just sending list of incremented integers. I would suggest you use some kind of randomly generated unique ids to expose over the api (this does not mean that you should get rid of integer base indices).
It is correct to handle the errors as soon as you detect them. In this case, the bad request is detected at controller level so it is the best option to handle it there.
Though your approach is fine, looking at #ResponseHandler may be instructive, as it can be used to generalize the handling of known exceptions, on Controller level.
I have the following method in my service layer.
public void delete(int candidateId) {
candidateRepository.delete(candidateId);
}
Pretty basic, now this method is used by the web layer which RESTful architecure is applied.
The URL that will trigger this method is:
DELETE /candidates/{id}
How should I deal with wrong ids given by the clients that use the REST API in the service layer? I know the HTTP response would be 4xx but how should I communicate that the id is invalid between the service and web layer?
Should I use a unchecked exception since this is a condition that my application is unable to recover from? The fault barrier (Spring exception handler) will deal with it.
Or should this be a checked exception since it is possible that clients give wrong ids?
I am using the latest Spring technology if that matter
If it is possible that clients give wrong ids, then they will give wrong ids. And this is a condition that your application should be able to recover from.
I would return a checked exception for this. But introducing a checked exceptions can sometimes mean changes throughout different layers of the application, because, for example, the signatures of many methods would need to be changed to add the "throws" clause (breaking OCP). In case that gets overcomplicated some people (like in Robert C. Martin's "Clean Code") recommend using unchecked exceptions. I would say it's up to you what to return as long as the exception has a meaningful description.
Firstly, you need to decide how your REST API will handle exceptions. There are multiple, equally valid solutions to this.
When designing an API, you pretty much have to assume that whatever can go wrong, will go wrong. Client applications will pass incorrect parameters, use incorrect formats, etc.; your application should expect this, and handle it gracefully.
Using exceptions to communicate business logic is not particularly readable, and may have performance implications. It really doesn't scale beyond very simple cases - imagine that the business logic for "delete" might need to include failures for "record not found", "record has dependent relationships", "record protected", "record archived" etc.
Instead, I would design the application to pass explicit status information back and forth, and translate this into whatever RESTful error handling you use.
I have a code which does a POST to a URL. The code uses setFixedLengthStreamingMode since it knows the length of POST in advance.
I am having a situation where in some cases the URL could be redirected to something else and since streaming mode is enabled; its not able to follow redirect.
Is there any way to do a check before actually posting the data to see if URL is getting redirected or not? Or am I thinking in wrong direction?
In general, no, there isn't. In a normal web use case though after a POST request done from a submit form you should always get a redirect as per best practices, but this is far from guaranteed. For example, it can do a request if data is similar, and not do it if it is something else. It can always fail with an error.
For some limited use cases there might be some logic that is always followed, but that is case-by-case thing then.
From documentation:
When output streaming is enabled, authentication and redirection
cannot be handled automatically. A HttpRetryException will be thrown
when reading the response if authentication or redirection are
required. This exception can be queried for the details of the error.
So while the redirect will not be handled automatically, and even though you cannot really check for redirect beforehand, what you can do is that you can catch the exception and perform steps yourself based on that.