Andrey Yaskulsky
Andrey Yaskulsky

Reputation: 2526

Spring - two different POST methods with the same URL but different produced content type

I have the following controller:

@RequiredArgsConstructor
@RestController
public class OwnerViewController implements ApiOwnerViewController {

    private static final String TEXT_CSV = "text/csv";

    private final PrivateOwnerFacade privateOwnerFacade;

    @PostMapping("/boat/v1/private-owners/search")
    public OwnerViewResponse searchOwners(@Valid @RequestBody SearchOwnersRequest request,
                                          Pageable pageable) {
        return privateOwnerFacade.findOwners(request, pageable);
    }

    @PostMapping(value = "/boat/v1/private-owners/search", produces = TEXT_CSV)
    public ResponseEntity<Resource> exportToCsv(@Valid @RequestBody SearchOwnersRequest request, Pageable pageable)
            throws IOException {

So I have two methods mapped to the same url and that both accept POST request BUT produce different content type - the first one produces application/json while the second produces text/csv.

Then, when I'm trying to make a request and set header Accept: text/csv I get 406 from the server.

I wonder if it is really possible to do such things with spring? Or is the only way to change second method so that it accepts GET requests?

Thanks

Upvotes: 4

Views: 4675

Answers (3)

Andrey Yaskulsky
Andrey Yaskulsky

Reputation: 2526

@RequiredArgsConstructor
@RestController
public class SearchController {

    @PostMapping(value = "/search", produces = {APPLICATION_JSON})
    public SearchResponse search(@Valid @RequestBody SearchRequest request,
                                          Pageable pageable) {
    }

    @PostMapping(value = "/search", produces = {TEXT_CSV})
    public ResponseEntity<Resource> export(@Valid @RequestBody SearchRequest request, Pageable pageable) throws IOException {

    }


}

Upvotes: 3

Nir Levy
Nir Levy

Reputation: 12953

the problem is that request with text/csv matches both endpoints.
you can use negative values on the annotation, so the first one will match only non-text/csv requests:

@PostMapping(value = "/boat/v1/private-owners/search", produces = "!text/csv")
public OwnerViewResponse searchOwners(@Valid @RequestBody SearchOwnersRequest 
                                      request,
                                      Pageable pageable) {
    return privateOwnerFacade.findOwners(request, pageable);
}

Upvotes: 1

phip1611
phip1611

Reputation: 6170

Just use one Method with a @PostMapping, return a response entity and dynamically set the Content-Type-Response-Header.

@RestController
public class TestController {

    @GetMapping("/api-endpoint")
    public ResponseEntity<String> method(@RequestParam("produces") String produces) {

        HttpHeaders responseHeaders = new HttpHeaders();

        if (produces.equals("text/csv")) {
            responseHeaders.setContentType(new MediaType("text", "csv"));
            return new ResponseEntity<String>("foo;bar", responseHeaders, HttpStatus.OK);
        } else {
            responseHeaders.setContentType(new MediaType("application", "json"));
            return new ResponseEntity<String>("{\"foo\": \"bar\"}", responseHeaders, HttpStatus.OK);
        }
    }
}

Upvotes: 0

Related Questions