RegisterRestClient WebApplicationException empty response entity - jax-rs

The problem is:
I have my #RegisterRestClient jaxrs client in quarkus.
Server replies 500. (Expected).
I then catch WebApplicationException thrown from calling the jaxrs client.
WebApplicationException has getResponse() method.
The problem is WAE.getResponse().readEntity() is empty.
The solution to this problem is actually known and described here:
https://github.com/quarkusio/quarkus/issues/17153#issuecomment-841573713
Also here: Resteasy error response body is unreachable
The question is: why is that call to WAE.getResponse().readEntity() throws a no entity exception?
It just seems counterintuitive.
I tried to enable http.wire logging and it appears httpclient reads the full error response body anyway. So performance probably was not an issue here.

Related

Handing unauthorized requests in WCF?

We have an WCF service, using webhttp binding. Users get authenticated, and then a method is called. In the method, we check a variety of settings associated with the user and some information specific to the request before knowing if the user is authorized to make the call.
Since this is WCF, I think I should be throwing a FaultException of some sort, but it's not clear if there is best practices.
My thoughts are that once I know what exception I will be throwing, I'd add a IErrorHandler which would set the headers correctly to 403.
Two questions:
1) Is there a standard FaultException for unauthorized requests? i.e. the equivalent of the http status code of 403?
2) Should I be able to handle the exceptions that I'll be throwing and change the response code to 403? Will I be able to pass through a custom error message? I've seen some posts that setting headers using the operation context in a catch does not get propagated to the client.
Ideally I'd be able to set the status to 403 with additional information like "You must be part of the administrators group to add a user"
Because you're using webhttp binding, traditional WCF fault management is not pertinent here and it's better to use WebFaultException and WebFaultException<>.
Public string MyOperation()
// Operation logic
// ...
throw new WebFaultException<string>("You must be part of the administrators group to add a user", HttpStatusCode.Forbidden);
}
As you think, it's very important to use standard HTTP status codes when developping an HTTP (REST-like) service.
It's been my experience that throwing fault exceptions, at least with wshttpbinding and basichttpbinding, can cause your web service to fail, so I don't recommend that approach.
If you want to send a message back to unauthorized users, just send an HTML response, setting the status to any one of the 400 responses that seem appropriate.
But from experience, fault exceptions, even if they're a controlled response to user actions and not from an actual processing error, will cause your web service to fail. I think they should be reserved genuine processing exceptions.
I went ahead and derived custom exceptions from FaultException, and then added an IErrorHandler to set the appropriate headers.
This seemed to be the best of both worlds. The code only throws exceptions derived from ones used in WCF, and all the handling specific to http binding is done via an IErrorHandler outside the business logic.

It is possible to configure Restlet to use BufferedHttpEntity?

I'm getting an intermittent exception org.apache.commons.httpclient.ProtocolException: Unbuffered entity enclosing request can not be repeated. when using Apache HTTP client library 4.x with Restlet 1.1. The request entity is of type InputRepresentation, which is associated with ByteArrayInputStream of known size, with size specified at the time of instantiation.
The exception is thrown in method writeRequestBody in class org.apache.commons.httpclient.methods.EntityEnclosingMethod
if ((this.repeatCount > 0) && !requestEntity.isRepeatable()) {
throw new ProtocolException(
"Unbuffered entity enclosing request can not be repeated.");
}
To be honest, the cause of this exception is not clear (especially due to its intermittent nature). However, some research suggests that using Apache BufferedHttpEntity to wrap the request entity should help.
Is there a way to inform Restlet to use BufferedHttpEntity when passing its request to the Apache library for handling? What could be the cause of the problem?
If the entity content stream can be reproduced (repeated), which is certainly the case with ByteArrayInputStream, there is no need for BufferedHttpEntity. One just needs to make sure that the original request entity returns a new instance of InputStream from HttpEntity#getContent() method and HttpEntity#isRepeatable() returns true.
Please note though that org.apache.commons.httpclient.ProtocolException is from an older (EOL-ed) version 3.x. Please make sure you do not have some kind of version mix-up in your application
This is a limitation of the Restlet Framework connector integrating with Apache HTTP Client.
In version 2.0 of RF, there is a new ClientResource class with "retryAttempts" and "retryDelay" property that provides the same behavior, but based on the Restlet abstractions.

How can I throw an exception from inside a WCF custom MessageEncoder and return it to the client?

In my WCF service I have implemented a custom encoder which inherits from System.ServiceModel.Channels.MessageEncoder.
In that encoder, I take the raw message and manipulate the received headers in my override of the ReadMessage() method.
During this manipulation, I may sometimes detect something in the header which makes the message invalid, and I want to return a useful exception to the client.
I have tried:
throw new Exception("Some useful message");
And:
throw new FaultException("Some useful message");
They both return an HTTP 400 to the client with no response body.
I can happily throw a FaultException from my actual web service method and this is returned to the client correctly, but at that late stage of the processing I no longer have access to the SOAP headers (unless someone can tell me otherwise).
How can I return a response 500 to the client with a friendly message based on information in the SOAP header?
You can call:
OperationContext.Current.IncomingMessageHeaders
in your service method to inspect the headers there if you wish. A custom MessageEncoder seems to me the wrong beast to be using to do what you describe.

Exception handler in a WCF REST service

I would like to create an exception handler in a WCF REST service. For Client recesse this exception in a simple way. I found many implementations using SOAP IErrorHandler for WCF, but none for REST. Could anyone help me with this?
Did you try using WebFaultException?
the exception information is provided in response message. Usually (in HTTP GET for REST), a result is expected as XML/JSON. In case of any error the error message is places instead of REST URI result.
http://www.robbagby.com/rest/effective-error-handling-with-wcf-rest/
WCF Rest Error Handling
IErrorHandler also works for WCF REST services, although you may need to know about how a non-SOAP (e.g., JSON) message is mapped inside the WCF Message object. The example at http://blogs.msdn.com/b/carlosfigueira/archive/2011/06/07/wcf-extensibility-ierrorhandler.aspx shows an error handler used to format responses to a JS client (in JSON).

Handling anything other than HttpStatusCode.OK

We have written a restful service using WCF and are now trying to write FitNesse tests to verify the behaviour of this service.
One test is that a 404 status code is returned if a resource can not be found.
The problem is that we can not find a mechanism for consuming the service that allows us to get the status code of the incomming response. Everything seems to work fine for everything other than 200. We have tried using HttpWebRequest and HttpWebResponse and the WebChannelFactory all of which throw exceptions of various types depending on the HttpStatusCode returned by the service.
Why can't I see the status code???!!
You can see the status code, in properties of the WebException that is thrown. You can get ex.Status. Then, you can get ex.Response, and access the status code.