ContainerRequestContext.abortWith(Response response) does not work - jax-rs

I tried RESTEasy's (WildFly 16) abortWith(Response response) but did not work. I have multiple abortWith medhods. Such as,
if(fails1){
System.out.printn("fails 1");
abortWith(...)
}
if(fails2){
System.out.printn("fails 2");
abortWith(...);
}
If fails1 and fails2 are true, both abortWith methods are executed. The fails1's abortWith does not return response unless I put "return".
if(fails1){
System.out.printn("fails 1");
abortWith(...);
return;
}
Do I need to put return after abortWith?
Can I throw WebApplicationException to break filter chain?

The ContainerRequestContext.abortWith() aborts the filter chain, not the current filter being processed. You can either add the return statement like you suggest or throw a WebApplicationException to raise and exception.

Related

ServerResponse returns before execution of Mono

I'm trying to validate the request body then based on it either return a bad request or proceed further. The issue is that the proceed flow is not executed. I'm attaching two solutions that I have tried:
Solution 1
public Mono<ServerResponse> startOrder(ServerRequest request) {
return request.bodyToMono(OrderDto.class)
.map(order -> Utils.validate(order))
.flatMap(listErrors -> {
if(listErrors.isEmpty()){
Mono<OrderResponse> orderResponseMono = this.service.startOrder(request.bodyToMono(OrderDto.class));
return ServerResponse.ok().body(orderResponseMono, OrderResponse.class);
}
Mono<OrderResponse> res = Mono.just(new OrderResponse(HttpStatus.BAD_REQUEST.value(), new ApiError(list.toString())));
return ServerResponse.badRequest().body(res, OrderResponse.class);
});
}
Solution 2
return request.bodyToMono(OrderDto.class)
.map(tt -> Utils.validate(tt))
.filter(res -> !res.isEmpty())
.map(r -> new OrderResponse(HttpStatus.BAD_REQUEST.value(), new ApiError("validation errors")))
.switchIfEmpty(this.service.initOrder(request.bodyToMono(OrderDto.class), HeaderValues.create(request.headers())))
.flatMap(res -> ServerResponse.badRequest().body(Mono.just(res), OrderResponse.class));
Validation method
public static List<String> validate(OrderDto request) {
List<String> result = new ArrayList<>();
if(request.getId == null){
result.add("Id should not be null");
}
if(request.getTitle() == null){
result.add("Title should not be null");
}
if(request.getDescription() == null){
result.add("Description should not be null");
}
return result;
}
When validation succeeds, the body with the result is returned but not when it fails.
What can cause the Mono to not be executed?
The issue you have is that you are trying to consume the response twice by calling response.bodyToMono(OrderDTO.class) two times in your code.
Once you have consumed the body from a response, the server will be able to close the connection to the called system.
If you call it multiple times it will (probably, not checked or verified) return a Mono.empty() which means it will not continue the flow as expected.
You should make it a habit of consuming the response body as quick as possible so that the server can close the connection to free up resources instead of passing around the response object.
Since we are working with streams, the connection will not be freed until the response is consumed.

Intellij: create a random number via IDE to use as error number / error code?

see here: The proper way to do exception handling
say this code:
function changeBookAuthor(int $id, string $newName){
if(!$newName){
throw new MyAppException('No author name was provided');
}
$book = Books::find($id);
if(!$book){
throw new MyAppException('The provided book id could not be found');
}
//..
}
i want to change that to:
function changeBookAuthor(int $id, string $newName){
if(!$newName){
throw new MyAppException('No author name was provided', <SOMEVERYRANDOMNUMBER>);
}
$book = Books::find($id);
if(!$book){
throw new MyAppException('The provided book id could not be found', <SOMEVERYRANDOMNUMBER>);
}
//..
}
can intellij help me in selecting random numbers?
I personally use different types of Exception instead of exception code.
For example:
try{
...
} catch (PDOException e1){
// Show a message that we could not do SQL work
} catch (NumberFormatException e2){
// Show a message that input was not a valid number
} catch (Exception e){
// I'm not sure what was wrong but definitely there was some thing wrong
}
But if you still want random numbers, go to https://www.random.org, there are some number generators, copy values and define them as constants in your code (i guess that you are using PHP)

return type for wep api for easy error handling

I have a web api which I call from my angularjs application. I have a method where (if all is OK) I return a list of strings. But if something goes wrong and I catch an exception, how should I handle this?
I'm quite new to this and I'm wondering how I should do about error handling? Are there any best practices for what return type I should use in a case like this?
1.
[HttpGet]
[Route("{user}")]
public IHttpActionResult GetItems(string user)
{
try
{
return Ok(adObject.GetItems(user)); //List of strings
}
catch (Exception e)
{
//return e how? Or log error? Both?
throw;
}
}
2.
[HttpGet]
[Route("{user}")]
public List<string> GetItems(string user)
{
return adObject.GetItems(user);
}
You should return a 500 http status code with enough information to tell the UI that an error occurred without revealing the inner workings of the API. For instance, you might say "unable to insert a new record". If the error is a result of the UI sending bad data, you would instead send a 400 series status code such as a 422.
To do all of this, there are two options. You can simply send back an InternalServerError like this:
[HttpGet]
[Route("{user}")]
public IHttpActionResult GetItems(string user)
{
try
{
return Ok(adObject.GetItems(user)); //List of strings
}
catch (Exception e)
{
Return InternalServerError();
LogError(e);
}
}
Which will just return a 500 error and log the the exception (you would need to write the LogError method).
You could also call ResponseMessage instead of InternalServerError and return your own HttpResponseMessage with more detail on the problem. Both of these methods are on the ApiController if you want to investigate their signatures or see others that you might be able to use.
The other option is to create a custom exception filter that inherits from ExceptionHandler. A good example of how to do this is available on this website:
http://www.brytheitguy.com/?p=29
Hope that helps.

Does Response.RedirectPermanent(); process code after it is called

I have the following code which checks an exception and if it is a 404 exception, it will check a list of urls to see if the page has been moved and if it matches, will issue a permanent redirect to the new page:
protected void Application_Error(object sender, EventArgs e)
{
var exception = Server.GetLastError();
if (exception != null)
{
if (exception is HttpException)
{
TryRedirect((HttpException)exception);
}
LogError(exception);
}
}
private void TryRedirect(HttpException httpException)
{
if (httpException.GetHttpCode() == 404)
{
WebsiteRedirect redirect = SiteCache.Redirects.FirstOrDefault(x => string.Compare(x.LegacyURL, HttpContext.Current.Request.RawUrl, true) == 0);
if (redirect != null)
{
// 301 it to the new url
Response.RedirectPermanent(redirect.NewURL);
}
}
}
Now I would expect that after the redirect has happened, non of the code after it would be executed ie the LogError function wouldn't be called. But it seems to be as I am getting error messages for the pages not being found.
Is this standard behaviour for MVC Response.RedirectPermanent?
Ok so as it turns out this is the standard behaviour as RedirectPermanent has 2 overloads (I never saw the second overload as my VS was playing up):
Response.RedirectPermanent(string url);
Response.RedirectPermanent(string url, bool endResponse);
The option of endResponse says that the permanent redirect will continue to finish the response or end the process immediately after the redirect.
The default is set to false meaning that the first overload (which is what I have used) will finish the response which is why it is calling the LogError function
When you are using response.RedirectPermanent() it will completely delegates the request.It's not going to execute or process any statement after Response.RedirectPermanent(redirect.NewURL) statement.
If you use Response.RedirectPermanent(string,boolean) method then give boolean value to true then it will execute your logerror(exception)
I request you to go through this link http://www.stepforth.com/blog/2008/redirects-permanent-301-vs-temporary-302/#.U7pxUfmSx-M
Response.RedirectPermanent(string url, bool endResponse);
return null;

How to Force an Exception from a Task to be Observed in a Continuation Task?

I have a task to perform an HttpWebRequest using
Task<WebResponse>.Factory.FromAsync(req.BeginGetRespone, req.EndGetResponse)
which can obviously fail with a WebException. To the caller I want to return a Task<HttpResult> where HttpResult is a helper type to encapsulate the response (or not). In this case a 4xx or 5xx response is not an exception.
Therefore I've attached two continuations to the request task. One with TaskContinuationOptions OnlyOnRanToCompletion and the other with OnlyOnOnFaulted. And then wrapped the whole thing in a Task<HttpResult> to pick up the one result whichever continuation completes.
Each of the three child tasks (request plus two continuations) is created with the AttachedToParent option.
But when the caller waits on the returned outer task, an AggregateException is thrown is the request failed.
I want to, in the on faulted continuation, observe the WebException so the client code can just look at the result. Adding a Wait in the on fault continuation throws, but a try-catch around this doesn't help. Nor does looking at the Exception property (as section "Observing Exceptions By Using the Task.Exception Property" hints here).
I could install a UnobservedTaskException event handler to filter, but as the event offers no direct link to the faulted task this will likely interact outside this part of the application and is a case of a sledgehammer to crack a nut.
Given an instance of a faulted Task<T> is there any means of flagging it as "fault handled"?
Simplified code:
public static Task<HttpResult> Start(Uri url) {
var webReq = BuildHttpWebRequest(url);
var result = new HttpResult();
var taskOuter = Task<HttpResult>.Factory.StartNew(() => {
var tRequest = Task<WebResponse>.Factory.FromAsync(
webReq.BeginGetResponse,
webReq.EndGetResponse,
null, TaskCreationOptions.AttachedToParent);
var tError = tRequest.ContinueWith<HttpResult>(
t => HandleWebRequestError(t, result),
TaskContinuationOptions.AttachedToParent
|TaskContinuationOptions.OnlyOnFaulted);
var tSuccess = tRequest.ContinueWith<HttpResult>(
t => HandleWebRequestSuccess(t, result),
TaskContinuationOptions.AttachedToParent
|TaskContinuationOptions.OnlyOnRanToCompletion);
return result;
});
return taskOuter;
}
with:
private static HttpDownloaderResult HandleWebRequestError(
Task<WebResponse> respTask,
HttpResult result) {
Debug.Assert(respTask.Status == TaskStatus.Faulted);
Debug.Assert(respTask.Exception.InnerException is WebException);
// Try and observe the fault: Doesn't help.
try {
respTask.Wait();
} catch (AggregateException e) {
Log("HandleWebRequestError: waiting on antecedent task threw inner: "
+ e.InnerException.Message);
}
// ... populate result with details of the failure for the client ...
return result;
}
(HandleWebRequestSuccess will eventually spin off further tasks to get the content of the response...)
The client should be able to wait on the task and then look at its result, without it throwing due to a fault that is expected and already handled.
In the end I took the simplest route I could think of: hide the exception. This is possible because WebException has a property Response which gives access to the HttpWebResponse I want:
var requestTask = Task<WebResponse>.Factory.FromAsync(
webReq.BeginGetResponse,
ia => {
try {
return webReq.EndGetResponse(ia);
} catch (WebException exn) {
requestState.Log(...);
return exn.Response;
}
});
And then handle errors, redirects and success responses in the continuation task.