Open5
APIでファイルをアップロードする方法について理解したい

参考記事

APIでファイルを送信する方法は主に「multipart/form-data」と「Base64エンコード」の2つ

multipart/form-dataとは
HTTPリクエストのContent-Typeの1つ
主にフォームからファイルをアップロードする際に使用される
使用例
フォームでユーザー名を入力 &アバター画像を選択する例
このフォーム送信時、ブラウザはContent-Type: multipart/form-dataを使ってリクエストボディを構成する
<form action="/upload" method="POST" enctype="multipart/form-data">
<input type="text" name="username" />
<input type="file" name="avatar" />
<button type="submit">送信</button>
</form>
各パートはboundary(境界線)によって区切られる
boundaryはContent-Typeヘッダーの一部です
下記のboundaryは----WebKitFormBoundary12345
Content-Dispositionはデータについてサーバーに情報を伝えるために使用している
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary12345
------WebKitFormBoundary12345
Content-Disposition: form-data; name="username"
naoki
------WebKitFormBoundary12345
Content-Disposition: form-data; name="avatar"; filename="profile.png"
Content-Type: image/png
(binary data...)
------WebKitFormBoundary12345--

NestJSでファイルアップロードAPIを実装してみた(ファイルデータの受け取り側)
@Post('image')
async uploadImage(@Req() req: FastifyRequest): Promise<void> {
// Fastifyでファイルを取得(filenameやfile(Stream)が含まれる)
const fileData = await req.file()
// ファイルの拡張子を抽出するメソッドを実行(profile.pngの場合はpng)
// ファイルをアップロードする際にファイル形式を明示するため
const extension = extractExtension(fileData.filename)
// ファイルのバイナリデータのストリームと拡張子を渡して、画像のアップロード処理を実行
// ざっくりいうとファイルの実体がfileData.fileである
await this.xxxService.uploadImage(fileData.file, ext)
}
request.file()の中身
{
fieldname: 'avator',
filename: 'profile.png',
encoding: '7bit',
mimetype: 'image/png',
file: ReadableStream
}

NestJSでファイルアップロードAPIを実装してみた(ファイルデータの送信側)
ストリームはバイナリデータなどのデータを少しずつ順番に処理する仕組み
[一括読み込み(Buffer)]
┌──────────────┐
│ すべてのデータを読み込み │ → 保存・処理
└──────────────┘
↓
[ストリーム(Stream)]
┌────┐┌────┐┌────┐┌────┐
│Chunk│→│Chunk│→│Chunk│→│Chunk│→ 保存・処理
└────┘└────┘└────┘└────┘
下記のコードはデータのかたまりを少しずつ順番に送ってファイルをアップロードしている
await s3.upload({
Bucket: 'my-bucket',
Key: `images/${uuid()}.${extension}`
Body: fileData.file, // ストリームを直接渡す
ContentType: fileData.mimetype,
}).promise()
[アップロード元(サーバ)]
fileData.file
↓
┌────────┐
│ Chunk1 │ →┐
└────────┘ │
┌────────┐ │
│ Chunk2 │ →├─▶ Amazon S3
└────────┘ │
┌────────┐ │
│ Chunk3 │ →┘
└────────┘
[アップロード先(S3バケット)]