Whole Body Binding

When request part names aren’t known ahead of time, or to read the entire body, a special type can be used to indicate the entire body is desired.

If a route has an argument of type MultipartBody (not to be confused with the class for the client) annotated with @Body, each part of the request will be emitted through the argument. A MultipartBody is a publisher of CompletedPart instances.

For example:

Binding to the entire multipart body

  1. import io.micronaut.http.annotation.Body;
  2. import io.micronaut.http.annotation.Controller;
  3. import io.micronaut.http.annotation.Post;
  4. import io.micronaut.http.multipart.CompletedFileUpload;
  5. import io.micronaut.http.multipart.CompletedPart;
  6. import io.micronaut.http.server.multipart.MultipartBody;
  7. import org.reactivestreams.Publisher;
  8. import org.reactivestreams.Subscriber;
  9. import org.reactivestreams.Subscription;
  10. import reactor.core.publisher.Mono;
  11. import io.micronaut.core.async.annotation.SingleResult;
  12. import static io.micronaut.http.MediaType.MULTIPART_FORM_DATA;
  13. import static io.micronaut.http.MediaType.TEXT_PLAIN;
  14. @Controller("/upload")
  15. public class WholeBodyUploadController {
  16. @Post(value = "/whole-body", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) (1)
  17. @SingleResult
  18. public Publisher<String> uploadBytes(@Body MultipartBody body) { (2)
  19. return Mono.create(emitter -> {
  20. body.subscribe(new Subscriber<CompletedPart>() {
  21. private Subscription s;
  22. @Override
  23. public void onSubscribe(Subscription s) {
  24. this.s = s;
  25. s.request(1);
  26. }
  27. @Override
  28. public void onNext(CompletedPart completedPart) {
  29. String partName = completedPart.getName();
  30. if (completedPart instanceof CompletedFileUpload) {
  31. String originalFileName = ((CompletedFileUpload) completedPart).getFilename();
  32. }
  33. }
  34. @Override
  35. public void onError(Throwable t) {
  36. emitter.error(t);
  37. }
  38. @Override
  39. public void onComplete() {
  40. emitter.success("Uploaded");
  41. }
  42. });
  43. });
  44. }
  45. }

Binding to the entire multipart body

  1. import io.micronaut.http.annotation.Body
  2. import io.micronaut.http.annotation.Controller
  3. import io.micronaut.http.annotation.Post
  4. import io.micronaut.http.multipart.CompletedFileUpload
  5. import io.micronaut.http.multipart.CompletedPart
  6. import io.micronaut.http.server.multipart.MultipartBody
  7. import org.reactivestreams.Subscriber
  8. import org.reactivestreams.Subscription
  9. import reactor.core.publisher.Mono
  10. import static io.micronaut.http.MediaType.MULTIPART_FORM_DATA
  11. import static io.micronaut.http.MediaType.TEXT_PLAIN
  12. @Controller("/upload")
  13. class WholeBodyUploadController {
  14. @Post(value = "/whole-body", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) (1)
  15. Mono<String> uploadBytes(@Body MultipartBody body) { (2)
  16. Mono.<String>create({ emitter ->
  17. body.subscribe(new Subscriber<CompletedPart>() {
  18. private Subscription s
  19. @Override
  20. void onSubscribe(Subscription s) {
  21. this.s = s
  22. s.request(1)
  23. }
  24. @Override
  25. void onNext(CompletedPart completedPart) {
  26. String partName = completedPart.name
  27. if (completedPart instanceof CompletedFileUpload) {
  28. String originalFileName = completedPart.filename
  29. }
  30. }
  31. @Override
  32. void onError(Throwable t) {
  33. emitter.error(t)
  34. }
  35. @Override
  36. void onComplete() {
  37. emitter.success("Uploaded")
  38. }
  39. })
  40. })
  41. }
  42. }

Binding to the entire multipart body

  1. import io.micronaut.http.MediaType.MULTIPART_FORM_DATA
  2. import io.micronaut.http.MediaType.TEXT_PLAIN
  3. import io.micronaut.http.annotation.Body
  4. import io.micronaut.http.annotation.Controller
  5. import io.micronaut.http.annotation.Post
  6. import io.micronaut.http.multipart.CompletedFileUpload
  7. import io.micronaut.http.multipart.CompletedPart
  8. import io.micronaut.http.server.multipart.MultipartBody
  9. import org.reactivestreams.Subscriber
  10. import org.reactivestreams.Subscription
  11. import reactor.core.publisher.Mono
  12. @Controller("/upload")
  13. class WholeBodyUploadController {
  14. @Post(value = "/whole-body", consumes = [MULTIPART_FORM_DATA], produces = [TEXT_PLAIN]) (1)
  15. fun uploadBytes(@Body body: MultipartBody): Mono<String> { (2)
  16. return Mono.create { emitter ->
  17. body.subscribe(object : Subscriber<CompletedPart> {
  18. private var s: Subscription? = null
  19. override fun onSubscribe(s: Subscription) {
  20. this.s = s
  21. s.request(1)
  22. }
  23. override fun onNext(completedPart: CompletedPart) {
  24. val partName = completedPart.name
  25. if (completedPart is CompletedFileUpload) {
  26. val originalFileName = completedPart.filename
  27. }
  28. }
  29. override fun onError(t: Throwable) {
  30. emitter.error(t)
  31. }
  32. override fun onComplete() {
  33. emitter.success("Uploaded")
  34. }
  35. })
  36. }
  37. }
  38. }