Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jersey Client / JAX-RS and optional (not default) @QueryParam (client side)

I have a RESTful API who's document says that a certain query parameter is optional, and does not supply a default argument. So, I can either supply the value or not send it in the GET request as a parameter.

Example:

  • queryA is required
  • queryB is optional (can send GET without it)

This should work:

http://www.example.com/service/endpoint?queryA=foo&queryB=bar

This should also work:

http://www.example.com/service/endpoint?queryA=foo

How do I make an client interface for Jersey-Proxy that can do this?? I do not have the server-side code to interface with so I am using org.glassfish.jersey.client.proxy.WebResourceFactory via Jersey-Proxy to generate the client to interact with the server API.

Sample interface:

import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/service")
@Produces("application/json")
public interface ServiceInterface {

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first,
            @QueryParam("queryB") String second);

}

I know I can make another method:

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first);

But what happens when you have multiple optional fields?? I don't want to make every possible mutation of them!

like image 694
justderb Avatar asked May 10 '15 02:05

justderb


People also ask

What is Jersey and JAX-RS?

JAX-RS is an specification (just a definition) and Jersey is a JAX-RS implementation. Jersey framework is more than the JAX-RS Reference Implementation. Jersey provides its own API that extend the JAX-RS toolkit with additional features and utilities to further simplify RESTful service and client development.

Can query Param be optional?

As query parameters are not a fixed part of a path, they can be optional and can have default values.


2 Answers

The interface was right all along

I can't believe it was this easy:

import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/service")
@Produces("application/json")
public interface ServiceInterface {

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first,
            @QueryParam("queryB") String second);

}

Notice anything different than the questions interface?? Nope. That's because that is the answer!


Don't use @DefaultValue for optional parameters

If you want to default a parameter to a specific value, you use the @DefaultValue annotation in the parameter:

import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/service")
@Produces("application/json")
public interface ServiceInterface {

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first,
            @QueryParam("queryB") @DefaultValue("default") String second);

}

Pass null to the @QueryParam you don't want

If you want to make the @QueryParam optional, you do not apply the @DefaultValue annotation. To pass a value with the query parameter, just pass in the value normally. If you would like the query parameter to not show up at all, just pass null!

import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/service")
@Produces("application/json")
public interface ServiceInterface {

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first,
            // Pass null to this parameter to not put it in the GET request
            @QueryParam("queryB") String second);

}

So calling ServiceInterface.getEndpoint("firstQueryParam", "secondQueryParam"); calls:

http://targethost.com/service/endpoint?queryA=firstQueryParam&queryB=secondQueryParam

and calling ServiceInterface.getEndpoint("firstQueryParam", null); calls:

http://targethost.com/service/endpoint?queryA=firstQueryParam

And walla! No second query parameter! :)

Note on primitive values

If your API takes primitive values (like int, float, boolean, etc), then use the object wrapper class (Autoboxing) for that primitive (like Integer, Float, Boolean, etc). Then, you can pass null to the method:

public Response getEndpoint(@QueryParam("queryA") Boolean first);
like image 114
justderb Avatar answered Oct 13 '22 13:10

justderb


You can inject a UriInfo instance (or something else like HttpServletRequest) into your method, and get whatever data you want off of it.

For example

@Path("/endpoint")
@GET
public Response getEndpoint(@Context UriInfo info, @QueryParam("queryA") String queryA) {
  String queryB = info.getQueryParameters().getFirst("queryB");
  if (null != queryB) {
    // do something with it
  }
  ...
}
like image 28
Alex Avatar answered Oct 13 '22 13:10

Alex