👻

【Vue.js × node(Nest.js)】AWS S3に画像をアップロードしてみた②

2023/01/01に公開約3,400字1件のコメント

はじめに/概要

Vue(フロントエンド)とnode(Nest(バックエンド))を使って、AWSのS3に画像をアップロードする方法を紹介します。

フロントエンドとバックエンドを組み合わせてS3に画像をアップロードする記事があまり見つからなかったので参考になれば嬉しいです。

今回の記事では、フロントエンド側から渡された画像データ(ここまでは、前回までの記事)を、バックエンド側からS3にアップロードする方法を紹介します。

対象

S3に画像をアップロードしてみたい方/方法がわからない方

目標

Vue.jsとNest.jsを使って、AWS S3に画像をアップロードできる。

事前準備

Vue.jsとNest.jsの環境構築ができているとします。
AWSアクセスキーの発行ができている状態だとします。

【バックエンド側】の実装

バックエンド側から画像データをS3にアップロードする処理を実装していきます。
バックエンド側は様々な処理が入り組んでいるため、わかりやすようにサービスクラスとコントローラーを分けて記載しています。

サービスクラスの実装

実際に、S3に画像データをアップロードする処理です。
s3に画像をアップロードする、ファイル名が重複してはいけないため、uuidv4関数を使ってランダムなIDを振っています。

s3にアップロードする際のパラメータにバケット名が必要なので、事前にバケットは作成しておいてください。

s3.service.ts
import { Injectable } from '@nestjs/common'
import { v4 as uuidv4 } from 'uuid'
import { S3 } from 'aws-sdk'

@Injectable()
export class S3Service {
  state = uuidv4()
  async upload(file: Express.Multer.File) {
    const { originalname } = file
    const fileName = `${this.state}-${originalname}`
    const s3 = new S3()
    const params = {
      Bucket: 'ここでBucket名を指定する',
      Key: fileName,
      Body: file.buffer,
    }
    return new Promise((resolve, reject) => {
      s3.upload(params, (err: any, data: any) => {
        if (err) {
          reject(err.message)
        } else {
          resolve(data)
        }
      })
    })
  }
}

S3のコントローラーの実装

フロントエンド側から叩いた先のAPIがこちらになります。
上記で記載したサービスクラスを呼び出して、画像データを渡します。

最後に、サービスクラスから返ってきたレスポンスデータを、フロントエンド側に返します。
フロントエンドに返した後の処理は前回の記事で実装しています。

※UseInterceptorsは、リクエストを受け取る前にロジックをbindできます(=ファイルの取得処理を間に入れることが可能)

s3.controller.ts
import {
  Controller,
  Post,
  Param,
  UploadedFile,
  HttpException,
  HttpStatus,
  Body,
} from '@nestjs/common'
import { FileInterceptor } from '@nestjs/platform-express'
import { CreateImageRequest, CreateS3Response } from './dto/create-s3.dto'
import { S3Service } from './s3.service'

@Controller('s3')
export class S3Controller {
  constructor(
    private readonly s3Service: S3Service,
  ) {}
  @Post('upload')
  @UseInterceptors(FileInterceptor('file'))
  async upload(
    @Body() createImageRequest: CreateImageRequest,
    @UploadedFile() file: Express.Multer.File
  ) {
    return await this.s3Service
      .upload(file)
      .then((data: any) => {
        return {
          path: data?.Location as string,
        }
      })
      .catch((e) => {
        if (e instanceof HttpException) {
          this.logger.error(
            LogService.createErrorMessage(e.getStatus(), e.message)
          )
          throw e
        } else {
          this.logger.error('INTERNAL_SERVER_ERROR', e)
          throw new HttpException(e, HttpStatus.INTERNAL_SERVER_ERROR)
        }
      })
  }
}


S3用のモジュール作成

app.module.tsで、サービスクラスやコントローラーを定義しなくても良いように(ごちゃごちゃにならないように)、s3用のモジュールを作成しておきます。

s3.module.ts
import { Module } from '@nestjs/common'
import { S3Service } from './s3.service'
import { S3Controller } from './s3.controller'

@Module({
  controllers: [S3Controller],
  providers: [S3Service],
})
export class S3Module {}

続いて、今作成したモジュールを使用できるようにapp.module.tsにimportします。

import { Module } from '@nestjs/common'
import { S3Module } from './modules/s3/s3.module'

@Module({
  imports: [
    S3Module,
  ],
})
export class AppModule {}


最後に

バックエンド側でs3に画像をアップする方法を記事にしました。
どなたかの参考になれば嬉しいです!

以上で終了です。お疲れ様でした!
参考になった方は、ぜひ、いいねをいただけると嬉しいです!

Discussion

記事へのコメント失礼します。株式会社KICONIA WORKSの海保と申します。
画像加工に関して記事を書かれていたので、弊社で企画中のサービスについてインタビュー(web会議/謝礼あり)でご意見を頂きたくご連絡しました。
画像加工(フォーマット変換、サムネイリング、メディアごとの出し分け等)の開発・運用を、会社もしくは個人でしている人を探しているのですが、いかがでしょうか?
(詳細はmailやSNS等でやりとりさせてください)

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