P_M
P_M

Reputation: 2942

Spring Reactive Web Applications POST Request body is missing

I work on small test project to check how Spring Reactive Web Applications actually works with MongoDB.

I follow the manual from https://docs.spring.io/spring/docs/5.0.0.M4/spring-framework-reference/html/web-reactive.html

and it states that I can process POST request in controller like:

@PostMapping("/person")
    Mono<Void> create(@RequestBody Publisher<Person> personStream) {
        return this.repository.save(personStream).then();
    }

Though this seems not works. Here the controller I implemented:

https://github.com/pavelmorozov/reactor-poc/blob/master/src/main/java/com/springreactive/poc/controller/BanquetHallController.java

it have just one POST mapping and it is very simple:

@PostMapping("/BanquetHall")
    Mono<Void> create(@RequestBody Publisher<BanquetHall> banquetHallStream) {
        return banquetHallRepository.insert(banquetHallStream).then();
    }

It is called each time I issue a POST with curl:

curl -v -XPOST -H "Content-type: application/json" -d '{"name":"BH22"}' 'http://localhost:8080/BanquetHall'
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /BanquetHall HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.47.0
> Accept: */*
> Content-type: application/json
> Content-Length: 15
> 
* upload completely sent off: 15 out of 15 bytes
< HTTP/1.1 200 OK
< content-length: 0
< 
* Connection #0 to host localhost left intact

And I see new objects stored in mongodb, but they not contain data. To debug I build simple subscriber, to see the data actually passed as request body to controller:

Subscriber s = new Subscriber() {
    @Override
    public void onSubscribe(Subscription s) {
        logger.info("Argument: "+s.toString());
    }
    @Override
    public void onNext(Object t) {
        logger.info("Argument: "+t.toString());

    }
    @Override
    public void onError(Throwable t) {
        logger.info("Argument: "+t.toString());
    }
    @Override
    public void onComplete() {
        logger.info("Complete! ");
    }
};
banquetHallStream.subscribe(s);

and now I see after subscription onError method called. The Throwable states body missing:

Request Error 400

Here error string:
Request body is missing: reactor.core.publisher.Mono<java.lang.Void> com.springreactive.poc.controller.BanquetHallController.create(org.reactivestreams.Publisher<com.springreactive.poc.domain.BanquetHall>)

Why request body is empty?

Also good to know: As I new with all this reactive stuff, could it be some better approach to debug Publisher/Subscriber without manual implementing Subscriber?

Update I updated POST handler method description and it passes request body as String object:

Mono<Void> create(@RequestBody String banquetHallStream)

Then this is not a "Reactive", right? String is not reactive, as Publisher should be...

Upvotes: 4

Views: 10956

Answers (1)

Adrian
Adrian

Reputation: 3134

I had exact the same issue and was able to solve it by putting @ResponseStatus on method. Below is how method controller looks like:

@ResponseStatus(HttpStatus.CREATED)
@PostMapping(value = "/bulk", consumes = APPLICATION_STREAM_JSON_VALUE)
public Mono<Void> bulkInsert(@RequestBody Flux<Quote> quotes) {
    return quoteReactiveRepository.insert(quotes).then();
}

I'm doing the request to that endpoint using WebClient:

webClient.post()
        .uri("/quotes/bulk")
        .contentType(MediaType.APPLICATION_STREAM_JSON)
        .body(flux(), Quote.class)
        .retrieve()
        .bodyToMono(Void.class).block();

tested with: org.springframework.boot:spring-boot-starter-webflux:2.1.0.RELEASE

Upvotes: 2

Related Questions