4

I am trying to implement a web service that proxies another service that I want to hide from external users of the API. Basically I want to play the middle man to have ability to add functionality to the hidden api which is solr.

I have to following code:

@POST
@Path("/update/{collection}")
public Response update(@PathParam("collection") String collection,
        @Context Request request) {
      //extract URL params
      //update URL to target internal web service
      //put body from incoming request to outgoing request
      //send request and relay response back to original requestor
}

I know that I need to rewrite the URL to point to the internally available service adding the parameters coming from either the URL or the body.

This is where I am confused how can I access the original request body and pass it to the internal web service without having to unmarshall the content? Request object does not seem to give me the methods to performs those actions.

I am looking for Objects I should be using with potential methods that would help me. I would also like to get some documentation if someone knows any I have not really found anything targeting similar or portable behaviour.

Stainedart
  • 1,929
  • 4
  • 32
  • 53

2 Answers2

3

Per section 4.2.4 of the JSR-311 spec, all JAX-RS implementations must provide access to the request body as byte[], String, or InputStream.

You can use UriInfo to get information on the query parameters. It would look something like this:

@POST
@Path("/update/{collection}")
public Response update(@PathParam("collection") String collection, @Context UriInfo info, InputStream inputStream) 
{
     String fullPath = info.getAbsolutePath().toASCIIString();
     System.out.println("full request path: " + fullPath);

     // query params are also available from a map.  query params can be repeated,
     // so the Map values are actually Lists.  getFirst is a convenience method
     // to get the value of the first occurrence of a given query param
     String foo = info.getQueryParameters().getFirst("bar");

     // do the rewrite...
     String newURL = SomeOtherClass.rewrite(fullPath);

     // the InputStream will have the body of the request.  use your favorite
     // HTTP client to make the request to Solr.
     String solrResponse = SomeHttpLibrary.post(newURL, inputStream);

     // send the response back to the client
     return Response.ok(solrResponse).build();

One other thought. It looks like you're simply rewriting the requests and passing through to Solr. There are a few others ways that you could do this.

If you happen to have a web server in front of your Java app server or Servlet container, you could potentially accomplish your task without writing any Java code. Unless the rewrite conditions were extremely complex, my personal preference would be to try doing this with Apache mod_proxy and mod_rewrite.

There are also libraries for Java available that will rewrite URLs after they hit the app server but before they reach your code. For instance, https://code.google.com/p/urlrewritefilter/. With something like that, you'd only need to write a very simple method that invoked Solr because the URL would be rewritten before it hits your REST resource. For the record, I haven't actually tried using that particular library with Jersey.

John R
  • 2,066
  • 1
  • 11
  • 17
1

1/ for the question of the gateway taht will hide the database or index, I would rather use and endpoint that is configured with @Path({regex}) (instead of rebuilding a regexp analyser in your endpoint) . Use this regex directly in the @path, this is a good practice.

Please take a look at another post that is close to this : @Path and regular expression (Jersey/REST)

for exemple you can have regexp like this one :

@Path("/user/{name : [a-zA-Z][a-zA-Z_0-9]}")

2/ Second point in order to process all the request from one endpoint, you will need to have a dynamic parameter. I would use a MultivaluedMap that gives you the possibility to add params to the request without modifying your endpoint :

@POST
@Path("/search")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces({"application/json"})
public Response search( MultivaluedMap<String, String> params ) {
    // perform search operations
    return search( params);

}

3/ My 3rd advice is Reuse : make economy and economy make fewer bugs. it's such a pitty to rewrite a rest api in order to perform solr search. You can hide the params and the endpoint, but could be great to keep the solr uri Rest formatting of the params in order to reuse all the search logic of solr directly in your api. This will make you perform a great economy in code even if you hide your solr instance behind you REST GATEWAY SERVER.

in this case you can imagine : 1. receive a query in search gateway endpoint 2. Transform the query to add your params, controls... 3. execute the REST query on solr (behind your gateway).

Community
  • 1
  • 1
jeorfevre
  • 2,286
  • 1
  • 17
  • 27
  • hum also another thing, if your query it to perform search, you should'nt use POST but GET. POST is used in order to create records not to read. – jeorfevre Apr 21 '15 at 01:13