0

I have a case where I need to implement a search. I want to pass a list of objects as query parameters. Below is a sample code.

Controller:

@RestController
@RequiredArgsConstructor
class RssFeedController {
    private final RssFeedFacade rssFacade;

    @GetMapping(value = "/rss", produces = MediaType.APPLICATION_JSON_VALUE)
    public RssFeedDto findRssFeed(@ModelAttribute FindRssFeedDto findRssFeedDto) {
        return rssFacade.findRssFeed(findRssFeedDto);
    }
    
}

Dto:

@Value
public class FindRssFeedDto {
    List<Author> authors;
    FeedStatus status;

    @Value
    public static class Author {
        String name;
        String authorId;
        // ...
    }

}

I tried to send GET request with list of objects in query parameter, in several different ways like:

  • authors=[{"name":"name","authorId":"authorId"}]
  • authors[0].name=name&authors[0].authorId=authorId

but list of authors is always null. I need to prepare a query that will allow me to search by many parameters. Is an additional custom deseriazlizer needed here?

KSs
  • 420
  • 3
  • 9
  • Please share what you tried, what do you mean by "several different ways" ? – Yann39 Apr 29 '23 at 19:37
  • @Yann39 examples added – KSs Apr 29 '23 at 19:52
  • 1
    Have you tried it as a post request? – fnymmm Apr 29 '23 at 19:53
  • Using POST and @RequestBody annotation will work, but i would like to implement it using the GET method – KSs Apr 29 '23 at 20:02
  • Any reason you use `@ModelAttribute` ? – Yann39 Apr 29 '23 at 20:04
  • It would be better to `POST` or `PUT` the data because query parameters aren't really suited to passing objects. However, if the objects all have the same fields you could pass multiple lists of values and reconstitute the objects in controller. This may help with that: https://stackoverflow.com/questions/4596351/binding-a-list-in-requestparam – Paul Apr 29 '23 at 20:06
  • I have a lot of potential query parameters with which I would like to extend the search. `@ModelAttribute` allow me to bind them all to an object and pass it to facade, instead of defining each parameter with `@RequestParam` annotation. – KSs Apr 29 '23 at 20:10

1 Answers1

2

Your second example should work, you should be able to pass the values this way :

https://example.com/rss?authors[0].name=Bob&authors[0].authorId=1&authors[1].name=Alice&authors[1].authorId=2&status=active

I just tried it locally in my environment and it works fine.

My test controller :

@GetMapping(value = "/rss", produces = MediaType.APPLICATION_JSON_VALUE)
public void findRssFeed(@ModelAttribute("test") Test test) {
    log.info("status {}", test.getStatus());
    for (Test.Author a : test.getAuthors()) {
        log.info("name {}", a.getName());
        log.info("id {}", a.getAuthorId());
    }
}

The Powershell GET request :

Invoke-WebRequest -Uri "http://localhost:8080/rss?authors[0].name=Bob&authors[0].authorId=123&authors[1].name=Alice&authors[1].authorId=456&status=active" -Method GET

Response :

c.c.g.controller.rest.TestController  : status active
c.c.g.controller.rest.TestController  : name Bob
c.c.g.controller.rest.TestController  : id 123
c.c.g.controller.rest.TestController  : name Alice
c.c.g.controller.rest.TestController  : id 456

Check that you correctly encode the URL if you are trying from your browser.

Anyway if you need to pass a large amount of data, or a very complex object, then using GET may not be the best idea, as everything has to be passed in the query string from the URL.

Even if you can use body in GET requests (any HTTP request message is allowed to contain a message body), this is not recommended and not considered a good practice.

If you need to send complex or large data, simply do a POST request, and send your data in the request body.

Yann39
  • 14,285
  • 11
  • 56
  • 84