DEV Community

Masui Masanori
Masui Masanori

Posted on • Edited on

3

[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

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs