DEV Community

Masui Masanori
Masui Masanori

Posted on • Edited on

[Micronaut] Receiving multipart/form-data

Intro

This time, I will try receiving files as "multipart/form-data".
As same as last time, I will use Undertow as a web server.

Receiving files

When using Undertow, I can't receive files using "io.micronaut.http.server.multipart.MultipartBody" as I wrote last time.

So I will use "@Part" annotations in this time.

FileController.java

package jp.masanori;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.micronaut.http.HttpHeaders;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Part;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.multipart.CompletedFileUpload;

@Controller("/files")
public class FileController {
    private final Logger logger;
    public FileController() {
        this.logger = LoggerFactory.getLogger(FileController.class);
    }
    @Post(uri="/sample", consumes = MediaType.MULTIPART_FORM_DATA, produces = MediaType.TEXT_PLAIN)
    public String uploadSampleFiles(HttpHeaders headers, @Part("file1") CompletedFileUpload file1) {
        logger.info("FileName: " + file1.getFilename() + " size: " + file1.getSize());
        return file1.getFilename();
    }
}
Enter fullscreen mode Exit fullscreen mode

To use the "@Part" annotation, I have to set "micronaut.server.multipart" enabled.

application.yml

micronaut:
    application:
        name: micronaut-web-app
    router:
        static-resources:
            default:
                enabled: true
                paths: classpath:static
    server:
        port: 8086
        multipart:
            # add this line
            enabled: true

            max-file-size: 20971520
Enter fullscreen mode Exit fullscreen mode

index.page.ts

window.Page = {
    send() {
        const file1Input = document.getElementById("upload_file_1") as HTMLInputElement;
        const file1 = getFile(file1Input.files);        
        const form = new FormData();
        // Must set "file1" even if there is no data 
        if(file1 == null) {
            form.append("file1", new Blob());
        } else {
            form.append("file1", file1);
        }       
        fetch("http://sample.masanori.jp:8086/files/sample", {
            method: "POST",
            mode: "cors",
            body: form
        }).then((res) => res.text())
        .then((res) => console.log(res))
        .catch(err => console.error(err));
    }
}
function getFile(files: FileList|null): File|null {
    if(files == null) {
        return null;
    }
    if(files.length <= 0 || files[0] == null) {
        return null;
    }
    return files[0];
}
Enter fullscreen mode Exit fullscreen mode

If the form data does't have the "file1" parameter, a "Bad Request" error will occur.

{
    "_links":{
        "self":[{"href":"/files/sample","templated":false}]},
        "_embedded":{"errors":[{
            "message":"Required Part [file1] not specified","path":"/file1"
            }]},
        "message":"Bad Request"
}
Enter fullscreen mode Exit fullscreen mode

I can receive two or more files like below.

FileController.java

...
@Post(uri="/sample", consumes = MediaType.MULTIPART_FORM_DATA, produces = MediaType.TEXT_PLAIN)
    public String uploadSampleFiles(HttpHeaders headers, @Part("file1") CompletedFileUpload file1,
    @Part("file2") CompletedFileUpload file2) {
...
    }
...
Enter fullscreen mode Exit fullscreen mode

Top comments (0)