[Micronaut] Receiving multipart/form-data
Tags: java, micronaut
Published: 2024-03-20 17:50:49

## 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.

* [[Micronaut] Try Cookie](https://dev.to/masanori_msl/micronaut-try-cookie-2ml7)

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

* [Try Micronaut](https://dev.to/masanori_msl/try-micronaut-41o4)

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

#### FileController.java
```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();
    }
}
```

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

#### application.yml
```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
```

#### index.page.ts
```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];
}
```

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"
}
```
I can receive two or more files like below.

#### FileController.java
```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) {
...
    }
...
```

* [Micronaut Servlet](https://micronaut-projects.github.io/micronaut-servlet/latest/guide/)