Джерси-клиент/JAX-RS и необязательный (не по умолчанию) @QueryParam (клиентская сторона)

У меня есть RESTful API, в документе говорится, что определенный параметр запроса является необязательным и не содержит аргумент по умолчанию. Таким образом, я могу либо указать значение, либо отправить его в запросе GET в качестве параметра.

Пример:

  • queryA требуется
  • queryB необязательный (можно отправить GET без него)

Это должно работать:

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

Это также должно работать:

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

Как создать клиентский интерфейс для Jersey-Proxy, который может это сделать? У меня нет серверного кода для взаимодействия, поэтому я использую org.glassfish.jersey.client.proxy.WebResourceFactory через Jersey-Proxy, чтобы создать клиент для взаимодействия с API-интерфейсом сервера.

Пример интерфейса:

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);

}

Я знаю, что могу сделать другой метод:

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

Но что происходит, когда у вас есть несколько необязательных полей? Я не хочу делать из них все возможные мутации!

Ответ 1

Интерфейс был правильным все время

Не могу поверить, что это было легко:

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);

}

Обратите внимание на что-то другое, чем на интерфейс вопросов? Неа. Это потому, что это ответ!


Не используйте @DefaultValue

Если вы хотите по умолчанию указать параметр для определенного значения, вы используете аннотацию @DefaultValue в параметре:

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);

}

Передать null в @QueryParam, который вам не нужен

Если вы хотите сделать @QueryParam необязательным, вы не применяете аннотацию @DefaultValue.. Чтобы передать значение с помощью параметра запроса, просто перейдите в значение как обычно. Если вы хотите, чтобы параметр запроса вообще не отображался, просто перейдите 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);

}

Таким образом, вызов ServiceInterface.getEndpoint("firstQueryParam", "secondQueryParam"); вызывает:

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

и вызов ServiceInterface.getEndpoint("firstQueryParam", null);:

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

И стена! Нет второго параметра запроса!:)

Ответ 2

Вы можете ввести экземпляр UriInfo (или еще что-то вроде HttpServletRequest) в свой метод и получить любые данные, которые вы хотите от него.

Например

@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
  }
  ...
}