How to forward a request using JAX-RS? - java

I want to forward a REST request to another server.
I use JAX-RS with Jersey and Tomcat. I tried it with setting the See Other response and adding a Location header, but it's not real forward.
If I use:
request.getRequestDispatcher(url).forward(request, response);
I get:
java.lang.StackOverflowError: If the url is a relative path
java.lang.IllegalArgumentException: Path http://website.com does not start with a / character (I think the forward is only legal in the same servlet context).
How can I forward a request?

Forward
The RequestDispatcher allows you to forward a request from a servlet to another resource on the same server. See this answer for more details.
You can use the JAX-RS Client API and make your resource class play as a proxy to forward a request to a remote server:
#Path("/foo")
public class FooResource {
private Client client;
#PostConstruct
public void init() {
this.client = ClientBuilder.newClient();
}
#POST
#Produces(MediaType.APPLICATION_JSON)
public Response myMethod() {
String entity = client.target("http://example.org")
.path("foo").request()
.post(Entity.json(null), String.class);
return Response.ok(entity).build();
}
#PreDestroy
public void destroy() {
this.client.close();
}
}
Redirect
If a redirect suits you, you can use the Response API:
Response.seeOther(URI): Used in the redirect-after-POST (aka POST/redirect/GET) pattern.
Response.temporaryRedirect(URI): Used for temporary redirection.
See the example:
#Path("/foo")
public class FooResource {
#POST
#Produces(MediaType.APPLICATION_JSON)
public Response myMethod() {
URI uri = // Create your URI
return Response.temporaryRedirect(uri).build();
}
}
It may be worth it to mention that UriInfo can be injected in your resource classes or methods to get some useful information, such as the base URI and the absolute path of the request.
#Context
UriInfo uriInfo;

Related

Catch all requested paths in Springboot RestController

I am looking for a way to get an Endpoint in Springboot that catches all requests send to /. Ideally everything behind / should be handed in as a String parameter.
An example request could look like this: http://myproxy.com/foo/bar?blah=blubb
I tried a RestController for /
#RestController
public class ProxyRestController {
#RequestMapping("/{restOfPath}", method = RequestMethod.GET)
public ResponseEntity<String> handleGetRequests(#PathVarialbe("restOfPath") String path) {
return ResponseEntity.of(Optional.of(""));
}
}
The endpoint doesn't catch the example because it would be routed to /foo/bar whereas /foo is caught.
How would I achieve a "catch all" endpoint in SpringBoot? It could also be in another way than a #RestController I just need to be inside a component and send a http response back to the caller.
Adapt this code to match yours:
#Controller
public class RestController {
#RequestMapping(value = "/**/{path:.*}")
public String index(final HttpServletRequest request) {
final String url = request.getRequestURI();
return "something";
}
}

Custom Arquillian ArquillianResteasyResource application path- Error HTTP method POST is not supported by this URL

My REST API works fine when deployed but my tests are failing using Jersey Arquillian extension:
#Test
#RunAsClient
public void postTest(#ArquillianResteasyResource final WebTarget webTarget) {
MyRequest request = new MyRequest();
String response = webTarget.path("/demo").request(MediaType.APPLICATION_JSON)
.post(Entity.json(request)).readEntity(String.class);
Assert.assertEquals("OK", response);
}
I get the error:
Error HTTP method POST is not supported by this URL
My JAX-RS programs look OK:
#ApplicationPath("api")
public class JaxRsActivator extends Application {
}
#Path("/demo")
#Stateless
public class DemoResource extends BaseResource {
#POST
public Response demo(MyRequest request) {
return Response.ok().entity("OK").build();
}
}
The default value for #ArquillianResteasyResource is rest, but my JaxRsActivator is set to api.
To solve it I used:
#ArquillianResteasyResource("api")
To get the complete URI: webTarget.getUri()

Find Jersey Parent Path

I have a Jersey 2.x endpoint that a user can POST to to update a specific property on a parent resource. On success, I would like to return a 303 status and specify the path to the parent resource in the Location header.
eg. if the user POSTed to:
http://example.com/api/v1/resource/field
then set the location header in the response to:
http://example.com/api/v1/resource
It seems like there should be a straightforward way to do this with UriInfo/UriBuilder, but I'm at a loss as to how to do it without hard-coding something that's likely to break later on.
Get the base URI (which assuming is http://example.com/api) from UriInfo.getBaseUriBuilder(), then append the XxxResource path with builder.path(XxxResource.class).
Then from the built URI, return Response.seeOther(uri).build();. Complete example:
#Path("/v1/resource")
public class Resource {
#GET
public Response getResource() {
return Response.ok("Hello Redirects!").build();
}
#POST
#Path("/field")
public Response getResource(#Context UriInfo uriInfo) {
URI resourceBaseUri = uriInfo.getBaseUriBuilder()
.path(Resource.class)
.build();
return Response.seeOther(resourceBaseUri).build();
}
}

Retrofit: How to get request properties in requestInterceptor

I need to apply an Authorization header in a request interceptor, but I need to sign the request method, URI, and date.
Inside the request interceptor I get a RequestInterceptor.RequestFacade, which only has "setter methods"
Is there any way I can get request properties inside a request interceptor?
Ah, did some more googling. The way to do this is to use a client wrapper. Observe...
public class SigningClient implements Client {
final Client wrapped;
public SigningClient(Client client) {
wrapped = client;
}
#Override public Response execute(Request request) {
Request newRequest = sign(request);
return wrapped.execute(newRequest);
}
private void sign(Request request) {
// magic
}
}
Found it here: https://github.com/square/retrofit/issues/185#issuecomment-17819547

Jersey Test Framework - define default error response for all unknown paths in grizzly

To test our API that connects to the facebook graph API we use a mock server setup based on Jersey Test Framework and grizzly:
#Path("/" + PostRest.RESOURCE)
#Produces("application/json")
public class PostRest {
public static final String RESOURCE = "111_222";
#GET
public Response getPost(#QueryParam("access_token") String access_token) {
if (access_token != VALID_TOKEN) {
return Response.status(400).entity(createErrorJson()).build();
}
return Response.status(200).entity(createSomeJsonString()).build();
}
Now while I can react to an invalid or missing access_token with the correct error response, I also want to test that my API reacts correctly when trying to access an unkown resource at facebook ie an unkown path.
Right now I get a 404 from my grizzly obviously, if I try to access say "/111_2", but facebook seems to catch that error and wrap it inside a Json response, containing the string "false" with status 200.
So... How do I set up the Test Framework to return
Response.status(200).entity("false").build();
every time it is called for an known path?
Basic example:
#ContextConfiguration({ "classpath:context-test.xml" })
#RunWith(SpringJUnit4ClassRunner.class)
public class SomeTest extends JerseyTest {
#Inject
private SomeConnection connection;
private String unkownId = "something";
public SomeTest() throws Exception {
super("jsonp", "", "com.packagename.something");
}
#Test(expected = NotFoundException.class)
public void testUnkownObjectResponse() throws NotFoundException {
// here it should NOT result in a 404 but a JSON wrapped error response
// which will be handled by the Connection class and
// result in a custom exception
connection.getObject(unkownId);
}
Or maybe I can set up grizzly to behave as desired..?!
Thanks!
Obviously facebook has it own service to intercept errors. Same thing should be done in your code. Just expose you own test service that intercepts all request
#Path("/test/errorTrap")
public class ErrorTrapService{
....
}
This service will produce any response you want. So any un-existing pages like http://mytest/test/errorTrap/111_2 will be intercepted by test service and produce expected response for you

Categories

Resources