6.13.1 Using the @Body Annotation

To parse the request body, you first indicate to Micronaut which parameter receives the data with the Body annotation.

The following example implements a simple echo server that echoes the body sent in the request:

Using the @Body annotation

  1. import io.micronaut.http.HttpResponse;
  2. import io.micronaut.http.MediaType;
  3. import io.micronaut.http.annotation.Body;
  4. import io.micronaut.http.annotation.Controller;
  5. import io.micronaut.http.annotation.Post;
  6. import javax.validation.constraints.Size;
  7. @Controller("/receive")
  8. public class MessageController {
  9. @Post(value = "/echo", consumes = MediaType.TEXT_PLAIN) (1)
  10. String echo(@Size(max = 1024) @Body String text) { (2)
  11. return text; (3)
  12. }
  13. }

Using the @Body annotation

  1. import io.micronaut.http.HttpResponse
  2. import io.micronaut.http.MediaType
  3. import io.micronaut.http.annotation.Body
  4. import io.micronaut.http.annotation.Controller
  5. import io.micronaut.http.annotation.Post
  6. import javax.validation.constraints.Size
  7. @Controller("/receive")
  8. class MessageController {
  9. @Post(value = "/echo", consumes = MediaType.TEXT_PLAIN) (1)
  10. String echo(@Size(max = 1024) @Body String text) { (2)
  11. text (3)
  12. }
  13. }

Using the @Body annotation

  1. import io.micronaut.http.HttpResponse
  2. import io.micronaut.http.MediaType
  3. import io.micronaut.http.annotation.Body
  4. import io.micronaut.http.annotation.Controller
  5. import io.micronaut.http.annotation.Post
  6. import javax.validation.constraints.Size
  7. @Controller("/receive")
  8. open class MessageController {
  9. @Post(value = "/echo", consumes = [MediaType.TEXT_PLAIN]) (1)
  10. open fun echo(@Size(max = 1024) @Body text: String): String { (2)
  11. return text (3)
  12. }
  13. }
1The Post annotation is used with a MediaType of text/plain (the default is application/json).
2The Body annotation is used with a javax.validation.constraints.Size that limits the size of the body to at most 1MB. This constraint does not limit the amount of data read/buffered by the server.
3The body is returned as the result of the method

Note that reading the request body is done in a non-blocking manner in that the request contents are read as the data becomes available and accumulated into the String passed to the method.

The micronaut.server.maxRequestSize setting in application.yml limits the size of the data (the default maximum request size is 10MB) read/buffered by the server. @Size is not a replacement for this setting.

Regardless of the limit, for a large amount of data accumulating the data into a String in-memory may lead to memory strain on the server. A better approach is to include a Reactive library in your project (such as Reactor, RxJava,or Akka) that supports the Reactive streams implementation and stream the data it becomes available:

Using Reactive Streams to Read the request body

  1. import io.micronaut.http.HttpResponse;
  2. import io.micronaut.http.MediaType;
  3. import io.micronaut.http.annotation.Body;
  4. import io.micronaut.http.annotation.Controller;
  5. import io.micronaut.http.annotation.Post;
  6. import javax.validation.constraints.Size;
  7. @Controller("/receive")
  8. public class MessageController {
  9. @Post(value = "/echo-publisher", consumes = MediaType.TEXT_PLAIN) (1)
  10. @SingleResult
  11. Publisher<HttpResponse<String>> echoFlow(@Body Publisher<String> text) { (2)
  12. return Flux.from(text)
  13. .collect(StringBuffer::new, StringBuffer::append) (3)
  14. .map(buffer -> HttpResponse.ok(buffer.toString()));
  15. }
  16. }

Using Reactive Streams to Read the request body

  1. import io.micronaut.http.HttpResponse
  2. import io.micronaut.http.MediaType
  3. import io.micronaut.http.annotation.Body
  4. import io.micronaut.http.annotation.Controller
  5. import io.micronaut.http.annotation.Post
  6. import javax.validation.constraints.Size
  7. @Controller("/receive")
  8. class MessageController {
  9. @Post(value = "/echo-publisher", consumes = MediaType.TEXT_PLAIN) (1)
  10. @SingleResult
  11. Publisher<HttpResponse<String>> echoFlow(@Body Publisher<String> text) { (2)
  12. return Flux.from(text)
  13. .collect({ x -> new StringBuffer() }, { StringBuffer sb, String s -> sb.append(s) }) (3)
  14. .map({ buffer -> HttpResponse.ok(buffer.toString()) });
  15. }
  16. }

Using Reactive Streams to Read the request body

  1. import io.micronaut.http.HttpResponse
  2. import io.micronaut.http.MediaType
  3. import io.micronaut.http.annotation.Body
  4. import io.micronaut.http.annotation.Controller
  5. import io.micronaut.http.annotation.Post
  6. import javax.validation.constraints.Size
  7. @Controller("/receive")
  8. open class MessageController {
  9. @Post(value = "/echo-publisher", consumes = [MediaType.TEXT_PLAIN]) (1)
  10. @SingleResult
  11. open fun echoFlow(@Body text: Publisher<String>): Publisher<HttpResponse<String>> { (2)
  12. return Flux.from(text)
  13. .collect({ StringBuffer() }, { obj, str -> obj.append(str) }) (3)
  14. .map { buffer -> HttpResponse.ok(buffer.toString()) }
  15. }
  16. }
1In this case the method is altered to receive and return an Publisher type.
2This example uses Project Reactor and returns a single item. Because of that the response type is annotated also with SingleResult. Micronaut only emits the response once the operation completes without blocking.
3The collect method is used to accumulate the data in this simulated example, but it could for example write the data to a logging service, database, etc. chunk by chunk
Body arguments of types that do not require conversion cause Micronaut to skip decoding of the request!