Optional params in REST API request using Jersey 2.21

前端 未结 2 1466
眼角桃花
眼角桃花 2020-12-10 14:29

I\'m playing around with Jersey 2.21 and I\'d like to know if it\'s possible to have an \"optional\" param which can, or not, be present in the request made to

相关标签:
2条回答
  • 2020-12-10 14:34

    So after some dabbling around with some of the answers in Optional @PathParam in Jax-RS, the problem is that using this

    @Path("/myMethod{id: (/\\d+)?}") 
    public Response get(@PathParam("id") int id) {}
    

    causes the / to be in the capture group. So when Jersey tries to parse /1 it will get an exception and send a 404. We could use a String, but then it gets ugly, as we need to get rid of the leading / and parse it ourselves.

    @Path("/myMethod{id: (/\\d+)?}") 
    public Response get(@PathParam("id") String id) {
        id = id.replace("/", "");
        int parsed = Integer.parseInt(id);
    }
    

    The other solution I came up with (the one that works for the OP), is to separate the / from the digits into two different path expressions, so that the leading / is not captured in the actual id and doesn't fail in parsing

    @Path("/method{noop: (/)?}{id: ((?<=/)\\d+)?}")
    public Response get(@PathParam("id") int id) {}
    

    The {noop: (/)?} captures the optional /. And the {id: ((?<=/)\\d+)?} uses a positive lookbehind, saying that the numbers (\\d+) are allowed if and only if there is a / before it ((?<=/)). This is necessary as the / is optional. If we didn't use this assertion, then /myMethod123 would be allowed.

    Here is a complete test case using Jersey Test Framework

    public class OptionalParamTest extends JerseyTest {
    
        @Path("optional")
        public static class Resource {
            @GET
            @Path("/method{noop: (/)?}{id: ((?<=/)\\d+)?}")
            public String get(@PathParam("id") int id) {
                return String.valueOf(id);
            }
        }
    
        @Override
        public ResourceConfig configure() {
            return new ResourceConfig(Resource.class);
        }
    
        @Test
        public void should_return_id_1() {
            Response response = target("optional/method/1").request().get();
            System.out.println("status=" + response.getStatus());
            assertEquals("1", response.readEntity(String.class));
        }
    
        @Test
        public void should_return_id_0_with_no_id() {
            Response response = target("optional/method").request().get();
            assertEquals(200, response.getStatus());
            assertEquals("0", response.readEntity(String.class));
        }
    
        @Test
        public void should_return_404_with_numbers_and_no_slash() {
            Response response = target("optional/method12").request().get();
            assertEquals(404, response.getStatus());
        } 
    
        @Test
        public void should_return_404_with_numbers_and_letters() {
            Response response = target("optional/method/12b").request().get();
            assertEquals(404, response.getStatus());
        }
    
        @Test
        public void should_return_404_with_only_letters() {
            Response response = target("optional/method/ab").request().get();
            assertEquals(404, response.getStatus());
        } 
    }
    

    Here's the dependency for the test

    <dependency>
        <groupId>org.glassfish.jersey.test-framework.providers</groupId>
        <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
        <version>${jersey2.version}</version>
        <scope>test</scope>
    </dependency>
    

    EDIT

    For the tests, it would be better to use a boxed Integer instead of an int as the method parameter. With the former you would be able to do a null check, instead of receiving the default 0 for the primitive.

    0 讨论(0)
  • 2020-12-10 14:37

    There is a way easier way to do this:

    @GET
    @Path("myMethod/{id}")
    public String myMethod(@PathParam("id") Integer id) {
    }
    
    @GET
    @Path("myMethod")
    public String myMethod() {
      return myMethod(null);
    }
    

    No tricky regex required.

    0 讨论(0)
提交回复
热议问题