Image upload Process

์žฅ์—ฌ์ง„ยท2022๋…„ 4์›” 23์ผ
0

Google Cloud Platform - Cloud Storage์ด์šฉ

๐Ÿ”ŽClient์—์„œ ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๋ฉด Server๋Š” Google Storage์— ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๊ณ  ํŒŒ์ผ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ Database์— ์ €์žฅ

[Google Storage์— ์ €์žฅํ•˜๋Š” ๋กœ์ง ์˜ˆ์‹œ]

  • Graphql๋กœ ํŒŒ์ผ์„ ๋ฐ›๊ธฐ ์œ„ํ•ด graphql-upload๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ
    yarn add graphql-upload
// main.ts 
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './commons/filter/http-exception.filter';
import * as dotenv from 'dotenv';
import * as cors from 'cors';
import { graphqlUploadExpress } from 'graphql-upload';
dotenv.config();

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalFilters(new HttpExceptionFilter());
  app.use(graphqlUploadExpress());  
  app.use(cors());
  await app.listen(3000);
}
bootstrap();
// file.resolver
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { FileService } from './file.service';
import { FileUpload, GraphQLUpload } from 'graphql-upload';

@Resolver()
export class FileResolver {
  constructor(
    private readonly fileService: FileService, //
  ) {}

  @Mutation(() => [String])
  async uploadCarFile(
    @Args({ name: 'files', type: () => [GraphQLUpload] }) files: FileUpload[],
  ) {
    return await this.fileService.upload({ files });
  }
}
//file.service
import { Injectable } from '@nestjs/common';
import { Storage } from '@google-cloud/storage';
import { FileUpload } from 'graphql-upload';
import { getToday } from 'src/commons/libraries/utils';
import { v4 as uuidv4 } from 'uuid';
interface IFile {
  files: FileUpload[]; //
}

@Injectable()
export class FileService {
  async upload({ files }: IFile) {
    const storage = new Storage({
      keyFilename: process.env.KEY_FILENAME,
      projectId: process.env.PROJECT_ID,
    }).bucket('codecamp-file-storage1');

    // ํŒŒ์ผ ๋จผ์ € ๋‹ค ๋ฐ›์•„๋†“๊ธฐ
    const waitedFiles = await Promise.all(files);

    const results = await Promise.all(
      waitedFiles.map((el) => {
        return new Promise((resolve, reject) => {
          const fname = `${getToday()}/${uuidv4}/orgin/${el.filename}`; // uuid๋กœ ์ค‘๋ณต์ด๋ฆ„ ๋ฐฉ์ง€ ๊ฐ€๋Šฅ
          el.createReadStream()
            .pipe(storage.file(el.filename).createWriteStream())
            .on('finish', () => {
              resolve(`codecamp-file-storage1/${fname}`);
            })
            .on('error', () => reject());
        });
      }),
    );

    console.log(results);
    return results;
  }
}

new Storage๋ฅผ ์ƒ์„ฑํ•˜์—ฌ storage๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๊ฐ’๋“ค์„ ๋„ฃ๊ธฐ(keyFilename, projectId)
new Promise๋ฅผ ์ด์šฉํ•ด์„œ file์„ createReadStream()์„ ์‚ฌ์šฉํ•ด์„œ ํŒŒ์ผ์„ ์ฝ๊ธฐ
pipe()๋ฅผ ์ด์šฉํ•ด์„œ 2์ฐจ์ ์ธ ์ž‘์—… ์‹คํ–‰(์‚ฌ์ด์ฆˆ์กฐ์ ˆ, ์ €์žฅ ๋“ฑ)
on()์œผ๋กœ ๊ฒฐ๊ณผ ๋‚˜ํƒ€๋‚ด๊ธฐ


๊ณต๋ถ€ํ•˜๋ฉฐ ์ž‘์„ฑํ•˜๊ณ  ์žˆ๋Š” ๋ธ”๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.
์ž˜๋ชป๋œ ๋‚ด์šฉ์ด ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ˜น์‹œ ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€ ๋‹ฌ์•„์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค ๐Ÿ˜Š

0๊ฐœ์˜ ๋Œ“๊ธ€