mat_e_44
mat_e_44

Reputation: 75

How to filter based on query parameter key and value with Spring

Our application submits jobs to another service on either a monthly or quarterly basis. We have an API that allows us to trigger one of the following scenarios:

  1. Submit a single job using its ID
  2. Submit all jobs that are scheduled to run each month
  3. Submit all jobs that are scheduled to run each quarter

Currently we have 3 different API endpoints for the 3 scenarios, but would like to update the API to use a structure similar to the following:

  1. /submit?type=single&id=123
  2. /submit?type=all&frequency=monthly
  3. /submit?type=all&frequency=quarterly

My question is how can we achieve this kind of mapping inside a Controller class so that each of the 3 API's has its own method, uniquely identified by the key-values provided to it.

Currently we have 3 methods similar to the following, which allows us to share the API path between the 3 methods, but differentiate them based on the params value. Is there a similar approach we could use that allows us to filter based on both the query param key and value?

@PostMapping(value = "/submit", params = "monthly")
@ResponseStatus(HttpStatus.ACCEPTED)
public void submitAllMonthlyJobs() {
// Code
}

One approach is to use a single method that handles all 3 scenarios, and inside that method we fork to one of the 3 options based on the query params. But I'm hopeful there's a cleaner approach where Spring handles this for us.

Thanks for your help.

Upvotes: 1

Views: 2333

Answers (1)

Roland Weisleder
Roland Weisleder

Reputation: 10531

Each request mapping like @RequestMapping, @GetMapping, @PostMapping etc. can be filtered not only by path, but also by params. Your endpoint with the three mappings could look like this:

@RestController
public class JobEndpoint {

    @PostMapping(path = "submit", params = "type=single")
    public void submitSingleJob(@RequestParam("id") long id) {
        System.out.println("submitting single job " + id);
    }

    @PostMapping(path = "submit", params = {"type=all", "frequency=monthly"})
    public void submitMonthlyJobs() {
        System.out.println("submitting monthly jobs");
    }

    @PostMapping(path = "submit", params = {"type=all", "frequency=quarterly"})
    public void submitQuarterlyJobs() {
        System.out.println("submitting quarterly jobs");
    }
}

And just to be sure that it works:

@WebMvcTest
@ExtendWith(OutputCaptureExtension.class)
class JobEndpointTest {

    @Autowired
    private MockMvc mvc;

    @Test
    void submitSingleJob(CapturedOutput output) throws Exception {
        mvc.perform(post("/submit?type=single&id=123")).andExpect(status().isOk());
        assertThat(output).contains("submitting single job 123");
    }

    @Test
    void submitMonthlyJobs(CapturedOutput output) throws Exception {
        mvc.perform(post("/submit?type=all&frequency=monthly")).andExpect(status().isOk());
        assertThat(output).contains("submitting monthly jobs");
    }

    @Test
    void submitQuarterlyJobs(CapturedOutput output) throws Exception {
        mvc.perform(post("/submit?type=all&frequency=quarterly")).andExpect(status().isOk());
        assertThat(output).contains("submitting quarterly jobs");
    }
}

Upvotes: 4

Related Questions