Is it possible to have a JAX-RS web service redirect to another web page?
Like as you would do with Servlet response.sendRedirect("http://test/test.html").
The JAX-RS web service should itself redirect. I'm using RESTEasy if that's relevant.
Yes, you can do this in Jersey or any JAX-RS implementation (including RestEasy) if your return type is a Response (or HttpServletResponse)
https://eclipse-ee4j.github.io/jersey.github.io/apidocs/1.19.1/jersey/javax/ws/rs/core/Response.html
You can use either of the following:
Response.temporaryRedirect(URI)
Response.seeOther(URI)
"Temporary Redirect" returns a 307 status code while "See Other" returns 303.
For those like me looking for 302 that fall on this answer.
By looking the code of
Response.temporaryRedirect(URI)
You can customize your response code like this :
Response.status(int).location(URI).build()
Note that status code are define in enum
Response.Status
And for example 302 is Response.Status.FOUND
Extending smcg# answer above,
You can achieve this by altering the request context in a ContainerRequestFilter by using ContainerRequestContext.setRequestUri(URI). If you see the JAX-RS specification (Section 6.2) here, there is a mention of #PreMatching request filters. According to the documentation;
A ContainerRequestFilter that is annotated with #PreMatching is executed upon
receiving a client request but before a resource method is matched. Thus, this type of filter has the ability
to modify the input to the matching algorithm (see Section 3.7.2) and, consequently, alter its outcome.
A very naive filter can be like this;
#PreMatching
class RedirectFilter: ContainerRequestFilter {
override fun filter(requestContext: ContainerRequestContext?) {
requestContext!!.setRequestUri(URI.create("<redirect_uri>"))
}
}
Related
I'm not sure how the interceptor works and what it is useful for. Also, why use the ClientHttpRequestInterceptor over AsyncClientHttpRequestInterceptor (or vice versa)?
In particular:
Should the intercept function be implemented on the front-end and back-end or is the back-end sufficient? How, where and when is the function called and how does data get passed to the function?
The only difference I can see between the regular interceptor and async from the docs is that in the regular you have the option to "wrap the response to filter HTTP attributes" and in async you have the option to "adapt the response to filter HTTP attributes with the help of the abstract class ListenableFutureAdapter."
I want to write filter, and get client httprequest before controller and make some code, depends on URL.
Request can be: HttpRequest, MultipartHttpServletRequest, can be POST or GET. I need to make request to another REST API, if the URL of this request starts with api.
You should use Spring org.springframework.web.servlet.HandlerInterceptor
(hopefully this answer explain how to use it)
(or you could use an simple Servlet-Filter - see also this question Spring HandlerInterceptor vs Servlet Filters it discuss the difference between them)
#Provider
public class JerseyExceptionMapper implements ExceptionMapper<JerseyException> {
#Override
public Response toResponse(JerseyException jerseyException) {
return Response.status(jerseyException.getErrorCode()).
entity(jerseyException.getJsonResponseObj()).
type(MediaType.APPLICATION_JSON).
build();
}
}
The code above has unwanted results when you're using an <error-page> component in the web.xml. For example, if my Response.status is set to 400 and my error-page component defines an <error-code> of 400, the web server will redirect the request to the location defined in the web.xml.
This is obviously not what I want for REST requests. I read another post on StackOverflow that said the reason a request gets diverted to the error-page is because HttpServletResponse.sendError(400) is set. That post said if you set HttpServletResponse.setStatus(400) instead, the error-page will be ignored.
If that is true, I don't see how it's helpful since I did not implement the Jersey code. The option I'm seeing is to investigate the Response class source code and possibly re-implement the status method or perhaps other Jersey code. Is there a simple option here or something I'm missing?
Essentially, my question is: Given that I'm using Jersey for REST and I'm using error-page in my web.xml, how can I use the above code while ignoring the error-page for Jersey code only? Any other code that causes HTTP errors should go to the error-page. Or is there another solution that doesn't involve error-page but will work identical to what I want?
I can reproduce the problem, but only if I pass a null as entity content.
Example:
return Response.status(400)
.entity(null)
.type(MediaType.APPLICATION_JSON)
.build();
or even
return Response.status(400)
.type(MediaType.APPLICATION_JSON)
.build();
Both will result in a redirect to the error-page which is set up for HTTP status code 400 because the container will use the sendError() method if no message content is specified.
But if you do it like this:
return Response.status(400)
.entity("An error occured.")
.type(MediaType.APPLICATION_JSON)
.build();
or this:
return Response.status(400)
.entity("")
.type(MediaType.APPLICATION_JSON)
.build();
the container/jersey will only use the setStatus() method and won't redirect to the error-page. As stated in the docs:
This method is used to set the return status code when there is no
error (for example, for the SC_OK or SC_MOVED_TEMPORARILY status
codes).
If this method is used to set an error code, then the container's
error page mechanism will not be triggered. If there is an error and
the caller wishes to invoke an error page defined in the web
application, then sendError(int, java.lang.String) must be used
instead.
So in your case the problem seems to be that jerseyException.getJsonResponseObj() returns null. You should implement a null-check to avoid this.
There is bug JERSEY-1557 for Jersey 1.x which describes the problem, it was closed without a fix but with the advice to use an empty entity string as a workaround.
There is also a similar bug open for Jersey 2.x: JERSEY-2673
See also:
JAX-RS — How to return JSON and HTTP Status code together?
how can i return response status 405 with empty entity?
Bean Validation 400 errors are returning default error page (html) instead of Response entity (json)
I want to understand how a RESTful web service identifies if a correct request method is called.
For example,
I have a REST service it exposes one operation which is of type GET.
Assume a REST client has invoked the operation using a wrong request method(PUT).
In this scenario, how the service/framework identifies a correct request method is invoked?
I have gone through various posts to understand the scenario but I don't find any information.
Please let me know your comments.
The first line sent in an HTTP request looks like this:
GET /index.html HTTP/1.1
The HTTP request thus contains the HTTP method (POST, PUT, GET, etc.). The framework reads this method, and invokes the Java method that is mapped (thanks to annotations, or XML configuration, or whatever) to the URL (also contained in the HTTP request, as shown above) and the HTTP method. If none is found, then an error response is sent back (405 Method Not Allowed, if the resource is found, but with another method, or 404 if the resource is not found).
It's the http protocol not REST that checks headers, and reports back with an error code.
REST is sort of a strategy, not an implementation.
Hope this helps.
I have variant resources that all extend BaseResource<T>
#Component
#Path("/businesses")
public class BusinessResource extends BaseResource<Business>{
#GET
#Path({businessId}/)
public Business getBusiness(#PathParam("businessId") Integer businessId){..}
}
#Component
#Path("/clients")
public class ClientResource extends BaseResource<Client>{
#GET
#Path({clientId}/)
public Client getClient(#PathParam("clientId") Integer clientId){..}
}
I would like, that when there is a call to
/businesses/3, it will first go through a method that I will write which validates the T object and if everything is ok I will tell jersey to continue handling the resource.
Same goes for Client.
I can't use a regular servlet/filter - since it's being called BEFORE jersey servlet and I wouldn't know which resource is being called.
What is the best way to do it in Jersey?
Is there a place to interfere between knowing the method that jersey will invoke and the invokation?
There are 4 basic http methods in REST, namly GET, PUT, POST, DELETE.
Your annotation tells Jersey what method to call when a http request occurs. Jersey looks up the target URI in the request and matches it against your model. If the request is a http get it will execute the method annotiated with #Get from the class with the correct #Path annotiaton.
Usually you dont want to grant access to your resources in this annotated method directly. A common (may not perfect) way is to implement a DAO class that handles access to your resources, and of course does the validation before it returns the resource back to the #Get annotated method, which will itself only pass the resource to the client. So you will get another layer in your application between persisting (SQL, etc) and the client interface (Jersey).
You can use jersey 2.x ContainerRequestFilters with NameBinding. After having matched the resource, the bound filter will be executed prior to executing the method itself.
You can see the Jersey user guide, which states that it is possible:
Chapter 9.2.1.1 explains about PreMatching and PostMatching filters and chapter 9.4 chapter shows the execution order of jersey filters.
See my post for the implementation where I had the problem to make the filters with jersey 2 work.