so lets say, i am listening on URL v1/shop/{PATH_PARAM}/status.xml. Whenever, a request is made at v1/shop/some_value/status.xml It will be redirected to my method.
But lets say, a user does a mistake in this path ? Jersey would by itself send an response of "Bad Request" or "Un implemented" method or something like that. Is there a way that instead jersey sending this response, I can handle those reponse ? lets say i will create a new function which will listen ot everything except for those which i are implemented for business case. So any request, which is not properly structured, or some unsupported media request would go to this method, so that i can send a more resonable response to the user
You could make a Servlet Filter, configure it to intercept all URLs matching your Web Services root URL (or even the root URL of the web server where the web service is deployed), have it pass the request on to the web service and then when the response arrives at the filter, if it's some kind of web service error you can change the response to whatever you want, make it redirect to some custom error page, etc.
I just did this using an "Exception Mapper". Here is a tutorial on how to do it with resteasy: https://community.jboss.org/wiki/RESTEasyExceptionHandlingWithExceptionMapper?_sscc=t
A colleague told me there is something analogous for Jersey.
Here is the code I used to make sure that I don't get empty content, because sometimes I forget, and I'm sure others will forget, to look at the headers / HTTP status.
import org.jboss.resteasy.spi.Failure;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
#Provider
public class PipelineMgrExceptionMapper implements ExceptionMapper<Exception> {
#Override
public Response toResponse(Exception e) {
if (e instanceof Failure) {
Failure f = (Failure) e;
return Response.fromResponse(f.getResponse()).entity(f.getMessage()).type(MediaType.TEXT_PLAIN).build();
} else {
return Response.status(500).entity(e.getMessage()).type(MediaType.TEXT_PLAIN).build();
}
}
}
Related
I am trying to make an API with Jetty Server, and I have this simple GET request:
#GET
public String helloWorld(){
return "Hello world";
}
In order to make a POST request, I assume that one must save the input to the Jetty server. I have tried to research for quite a while, but found nothing.
I imagine something like this:
#POST
public void Save(String stringToSave) {
// Save to DB?
}
You could likely google this but let me give you a quick overview. A Servlet is a chunk of code that is normally run during an HTTP action - GET, POST, etc. It is the original technology of the JavaEE world, having been released in the late 1990's.
A simple Java servlet, using modern annotations, would look something like:
#WebServlet(name = "SampleServlet", urlPatterns = "/sampleServlet")
public class SampleServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// called when an HTTP POST is sent
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// called when an HTTP GET is sent
}
}
The important parts to note are that the class extends HttpServlet and that you have to write code to pull data out of the request and push it into the response. This isn't bad to do but it does have to be done.
JAX-RS is a newer standard, aimed simplifying the creation of REST services. It too is a chunk of code that runs during an HTTP interaction.
A simple example of this would be:
#Path("/sampleService")
public class SampleService{
#Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#POST
#Path("/v1/hello")
public Response sayHello( SomeObject someobject ) {
The code here is both simpler and a bit more complex. The use of annotations helps determine the path that the service exists on a URL (in this case /sampleService/v1/hello), the HTTP method, and the Content-Type for both the request and response. Additionally, if the SomeObject object is defined correctly, the JAX-RS framework will automatically deserialize the incoming JSON or XML payload into an object for you.
The Response object contains the HTTP response code (perhaps a teapot) and a response body. In this example, the body will be automatically serialized back to the requestor in a way that matches the Accept header of the HTTP request (i.e., JSON for an application/json Accept header and XML for application/xml).
Note that while not directly related the JAX-RS framework takes advantage of the Servlet framework. Indeed in JAX-RS you can access the HttpServletRequest and HttpServletResponse object in your methods.
Which way is "better"? In general I would recommend using JAX-RS where possible as it is the newer standard and is a bit easier to implement. However, if you do any work in the JavaEE world you're very likely to run into Servlet code so it's important to understand it too.
Note that both Servlets and JAX-RS require an application server of some sort. Jetty is one of those. Another very common one is Tomcat. The application server sets up the environment for your code and listens for incoming HTTP messages. When it gets one it looks to see if it knows how to handle the URL and routes to the appropriate place. In the servlet world the server routes solely on the URL. In the JAX-RS world the server routes on the URL and, if specified by the #Consumes annotation, the HTTP Content-Type header too.
There is much more but let's start there and see if it answers what you're after.
I am writing some unit tests for a web service written years ago. The root class has a path like:
#Path("v1/path/")
public class RootResource {
...
}
The methods inside the class have their respective path. One working path is:
#GET
#Path("orders/{order_num}.xml")
#Produces(MediaType.APPLICATION_XML)
public Response getXML() {
...
}
This is working fine at root_path/v1/path/orders/123123.xml.
However, there is another method:
#POST
#Path("orders/{order_numer}/status.xml")
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public Response getStatusXML() {
Logger.info(CALLER, "orderStatusXML", "XML Request received");
...
}
When I try to access this at root_path/v1/path/orders/123423/status.xml I get 404 in return. Even the first line with the logger is missing from the logs.
I am on Weblogic 12 and we used Jersey REST API for these web services.
I have tried a number of things to make sure the path listed in the test case is the correct one. Any hints/ideas on how to check for the correct path?
There is no reason for the root_path/v1/path/orders/123423/status.xml path to give a 404 unless something else is acting on that URL.
Things to try:
look into your web.xml file and see what URL pattern Jersey handles. That particular URL might be handled by some other servlet;
again look into the web.xml and see if you have any filters declared. What URLs do does filters intercept and what do the filters do to the request once intercepted?
this might not be the case but I'll add it anyway... is it a "404 - Not found" that you get back or is it actually a "405 - Method not allowed" that is returned? If you try to access the root_path/v1/path/orders/123423/status.xml URL with a GET, like from the browser, you get 405 because your method is annotated with #POST. Are you using a POST?
My bet is on a filter!
As I have noticed, in my CXF JaxRS service, if I throw an exception in say READ phase (IN interceptor) and do not provide any default FaultOutInterceptor, the XMLFaultOutInterceptor takes care of building the response as it should be returned (which is always an XML).
Now, I would like to be able to return a response in the format in which the service was requested : JSON or XML or otherwise.
I found something like this on the web:
public class JsonFaultOutHandlerInterceptor extends JAXRSOutInterceptor
{
public JsonFaultOutHandlerInterceptor() {
getBefore().add(LoggingOutInterceptor.class.getName());
}
#Override
public void handleMessage(Message message) {
...
message.getInterceptorChain().abort();
}
}
I have configured it in the outInterceptor, should I conditionally abort (if the request type was application/Json) or not abort(if the request type was application/xml) the interceptor chain? (I'm not sure if the request type information is already available. Also, somehow, aborting the chain doesn't seem very correct)
Had the response reached the JAXRS filters, using ExceptionMapper<T> I would have beautifully handled the response. But when the exception occurs in the INinterceptor, I am a little lost.
What would be a good way to be able to define a FaultOutInterceptor?
We have REST services exposed via Spring MVC. We use a HandlerExceptionResolver to log exceptions. We currently log the following:
The exception and its stack trace
The URL
The request headers
It would make debugging easier if we could also log the JSON post data as well. Any suggestions on how to get this?
Add this to the class representing the configuration for the application:
import javax.servlet.Filter;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.filter.AbstractRequestLoggingFilter;
....
#Bean
public Filter loggingFilter(){
AbstractRequestLoggingFilter f = new AbstractRequestLoggingFilter() {
#Override
protected void beforeRequest(HttpServletRequest request, String message) {
System.out.println("beforeRequest: " +message);
}
#Override
protected void afterRequest(HttpServletRequest request, String message) {
System.out.println("afterRequest: " +message);
}
};
f.setIncludeClientInfo(true);
f.setIncludePayload(true);
f.setIncludeQueryString(true);
f.setBeforeMessagePrefix("BEFORE REQUEST [");
f.setAfterMessagePrefix("AFTER REQUEST [");
f.setAfterMessageSuffix("]\n");
return f;
}
you may have to comment out
f.setIncludePayload(true);
You need a filter that would save request body when it's being read and provide the saved data to your exception logger later.
Spring contains AbstractRequestLoggingFilter that does the similar thing. Though it's not directly suitable for your problem, you can use it as a reference to implement your own filter.
There is no easy way to log the payload of the request/response. You can use a java web filter to intercept all the requests and responses and read the JSON data from the stream. But there is one problem, when you will read data from the stream the actual data will be exhausted from stream.
Therefore, you have to implement the wrapper of actual request and response object. Only the copied version of request response will be logged. We have implemented similar solution like follows and it satisfied our requirement:
http://www.wetfeetblog.com/servlet-filer-to-log-request-and-response-details-and-payload/431
http://angelborroy.wordpress.com/2009/03/04/dump-request-and-response-using-javaxservletfilter/
I'm developing a REST-ful web service using RESTEasy deployed on Tomcat. I've configured an error page which takes the exception's message and generates an XML based on it when any exception occurs during the request.
This works fine for any application generated exceptions. However, if client sends an invalid XML which cannot be unmarshalled correctly, an javax.xml.bind.UnmarshalException is thrown and Tomcat's default error page is used instead of mine.
I have configured my error page to the error-code 500 in web.xml.
Is using error pages the correct way to handle errors when using RESTEasy or is there an alternative way?
The best way is to use an ExceptionMapper. You create a class UnmarshalExceptionMapper that implements ExceptionMapper. You annotate this with "#Provider" and in your Application constructor you do "classes.add(UnmarshalExceptionMapper.class)" or "singletons.add(new UnmarshalExceptionMapper())".
Your exception mapper will look something like this:
#provider
public class UnmarshalExceptionMapper
implements ExceptionMapper<UnmarshalException> {
public Response toResponse(UnmarshalException exception) {
ResponseBuilder rb =
Response.status(
Response.Status.BAD_REQUEST) // Most appropriate HTTP status code
.entity(your xml goes here)
.type("application/xml");
return rb.build();
}
}
Note that you must set the type to "application/xml" because currently content negotiation is NOT done for exception mappers. To do your own content negotiation, get the HttpHeaders from the request, find the "accept" header, and set the type accordingly.