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!
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);
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
}
...
}