🐡

NestJSで複数の画像をアップロードして、ローカルストレージに保存する

2022/12/12に公開約4,500字

NestJS で 1 つの画像をアップロードして、ローカルストレージに保存する の続編ですが、一通りの作成手順を記録します。

今回は複数の画像をアップロードしてみます。

最初に @types/multer をインストールします。

npm i -D @types/multer

interceptor を作成する

Controller で使うための interceptor を作成します。

src/posts/interceptors/index.ts
import { Request } from 'express';
import { parse } from 'path';
import { BadRequestException } from '@nestjs/common';

export const editFileName = (
  req: Request,
  file: Express.Multer.File,
  callback: (error: Error | null, filename: string) => void,
) => {
  const fileBaseName = parse(file.originalname).name;
  const fileExtName = parse(file.originalname).ext;
  const randomName = Array(4)
    .fill(null)
    .map(() => Math.round(Math.random() * 16).toString(16))
    .join('');
  callback(null, `${fileBaseName}-${randomName}${fileExtName}`);
};

export const imageFileFilter = (
  req: Request,
  file: {
    fieldname: string;
    originalname: string;
    encoding: string;
    mimetype: string;
    size: number;
    destination: string;
    filename: string;
    path: string;
    buffer: Buffer;
  },
  callback: (error: Error | null, acceptFile: boolean) => void,
) => {
  if (!file.originalname.match(/\.(jpg|jpeg|png|webp|gif|avif)$/)) {
    return callback(
      new BadRequestException('おいおい、画像だけを送ってくれよな?'),
      false,
    );
  }
  callback(null, true);
};

Controller を作成する

src/posts/posts.controller.ts
import {
  Controller,
  Post,
  UseInterceptors,
  UploadedFiles,
} from "@nestjs/common";

import { FileFieldsInterceptor } from "@nestjs/platform-express";
import { diskStorage } from "multer";
import { editFileName, imageFileFilter } from "./interceptors";

@Controller("posts")
export class PostsController {
  @Post("files")
  @UseInterceptors(
    FileFieldsInterceptor([{ name: "files", maxCount: 4 }], {
      storage: diskStorage({
        destination: "./files",
        filename: editFileName,
      }),
      fileFilter: imageFileFilter,
      limits: { fileSize: 1024 * 1024 * 4 },
    })
  )
  uploadFiles(
    @UploadedFiles()
    files: Array<Express.Multer.File>
  ): void {
    console.log(files);
  }
}

作ったコントローラをモジュールに登録する

src/posts/posts.module.ts
import { Module } from '@nestjs/common';
import { PostsService } from './posts.service';
import { PostsController } from './posts.controller';

@Module({
  controllers: [PostsController],
  providers: [PostsService],
})
export class PostsModule {}
src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PostsModule } from './posts/posts.module';

@Module({
  imports: [PostsModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Postman でファイルを送信してみる

http://localhost:3000/posts/files に対してリクエストを投げます。

Body > form-data の KEY に files を設定し、VALUE にファイルを選択します。
(KEY のセルの右端にTextFile を選ぶドロップダウンがあるので、Fileを選択します)

ファイルを 4 つ選んでリクエストを投げると、プロジェクトの files ディレクトリ以下に 4 つのファイルが保存されます。

コンソールには以下のように表示されます。

[Object: null prototype] {
  files: [
    {
      fieldname: 'files',
      originalname: 'sample1.jpeg',
      encoding: '7bit',
      mimetype: 'image/jpeg',
      destination: './files',
      filename: 'sample1-10710.jpeg',
      path: 'files/sample1-10710.jpeg',
      size: 213304
    },
    {
      fieldname: 'files',
      originalname: 'sample2.jpeg',
      encoding: '7bit',
      mimetype: 'image/jpeg',
      destination: './files',
      filename: 'sample2-9102a.jpeg',
      path: 'files/sample2-9102a.jpeg',
      size: 378541
    },
    {
      fieldname: 'files',
      originalname: 'sample3.jpeg',
      encoding: '7bit',
      mimetype: 'image/jpeg',
      destination: './files',
      filename: 'sample3-f09c.jpeg',
      path: 'files/sample3-f09c.jpeg',
      size: 300479
    },
    {
      fieldname: 'files',
      originalname: 'sample4.jpg',
      encoding: '7bit',
      mimetype: 'image/jpeg',
      destination: './files',
      filename: 'sample4-b7f8.jpg',
      path: 'files/sample4-b7f8.jpg',
      size: 149810
    }
  ]
}

5 つ以上のファイルを送信した場合

maxCount: 4 でファイル数を 4 つに制限しているため、5 つファイルを送ろうとすると以下のようにエラーが返されます。

{
  "statusCode": 400,
  "message": "Unexpected field",
  "error": "Bad Request"
}

参考

File upload

GitHubで編集を提案

Discussion

ログインするとコメントできます