동영상 업로드 기능이 있는 프로젝트를 진행하면서, 어떻게 하면 서버에 부담이 덜 가면서 파일 업로드를 할 수 있을까 고민했다.🤔
아래 사진은 원래 사용하려고 했던 multer를 이용한 파일 업로드이다.
파일이 브라우저 -> 서버 -> S3순으로 전달되며, 서버는 중간 다리 역할만 하고 있다.
상당히 비효율적이다🤣

그래서 이것 저것 찾다가 발견한 PRESIGNED URL😆을 사용해보기로 했다. 
S3 버켓에 이미지를 업로드 하기 위해서는 해당 S3에 대한 접근 권한을 인증해야 한다. 접근 권한에 대한 인증을 마치면 S3에 업로드 할 수 있는 URL을 발급해 주는데, 이 URL을 preSigned(pre-signed) URL라고 한다.

- 이미지 업로드 요청 시 서버 api 호출
 - S3 접근 권한을 가진 서버가 AWS S3에 preSignedURL 요청
 - AWS에서 preSignedURL을 return
 - 서버는 브라우저로 preSignedURL을 전달
 - 브라우저에서 AWS preSignedURL로 이미지 upload
 - 서버에게 해당 요청이 종료 되었음을 알림
 
aws-sdk를 사용한다.$ npm install aws-sdk
import { Body, Controller, HttpException, Post } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { ApiTags } from '@nestjs/swagger';
import AWS from 'aws-sdk';
import { v4 as uuid } from 'uuid';
import { IFileSignedUrl } from './fileSignedUrl.interface';
const AWS_S3_BUCKET_NAME = process.env.AWS_S3_BUCKET_NAME;
const s3 = new AWS.S3({ useAccelerateEndpoint: true });
AWS.config.update({
  accessKeyId: process.env.AWS_ACCESS_KEY_ID,
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
});
@ApiTags('Product')
@Controller('products')
export class ProductController {
  private imageS3Bucket: string;
  constructor() {}
  @Post('/signedUrl')
  async getSignedUrlForProductImage(
    @Body() { contentType, filePath }: IFileSignedUrl
  ): Promise<{
    fileName: string;
    s3Url: string;
  }> {
    if (!contentType) {
      throw new HttpException('Missing contentType', 400);
    }
    if (!filePath) {
      throw new HttpException('Missing filePath', 400);
    }
    const filetype: string = contentType.split('/')[1];
    // Rename file, I just want to show there is a way to rename file before you it into S3
    // Renaming file might be necessary for SEO
    const fileName: string = `${uuid()}.${filetype}`;
    const params = {
      Bucket: AWS_S3_BUCKET_NAME,
      Key: fileName,
      Expires: 3600,
      ContentType: contentType,
      ACL: 'public-read',
    };
    const s3Url = await s3.getSignedUrlPromise('putObject', params);
    return {
      fileName,
      s3Url,
    };
  }
}