[NestJS] .CSV 파일을 JSON 형태로 변환하기

2023. 8. 4. 09:16NestJS

변환에 앞서 새프로젝트 구성을 마쳤다는 가정하에 진행

변환에 필요한 파일 업로드를 처리할 엔드포인트 컨트롤러 생성

app.controller.ts

import {
  Controller,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ExcelService } from './excel.service';

@Controller()
export class AppController {
  constructor(private readonly excelService: ExcelService) {}

  @Post('/upload') // 데코레이터를 사용하여 '/upload' 엔드포인트에서 POST 요청을 처리
  @UseInterceptors(FileInterceptor('file')) // multipart/form-data로 전송된 파일을 받아옴
  async uploadFile(@UploadedFile() file) { // 업로드된 파일은 uploadFile(@UploadedFile() file) 함수의 인자로 주입
    const data = await this.excelService.convertCsvToJson(file.path);
    console.log(data);
    return data;
  }
}

다음은 필요한 서비스나 컨트롤러 등록을 합니다.

app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ExcelService } from './excel.service';
import { MulterModule } from '@nestjs/platform-express'; // 파일 업로드를 위한 설정을 등록
import { multerOptions } from './multer.options';

@Module({
  imports: [MulterModule.register(multerOptions)],
  controllers: [AppController],
  providers: [AppService, ExcelService], // provider로 등록하여, NestJS의 DI(Dependency Injection) 컨테이너를 통해 필요한 곳에 주입할 수 있도록 처리
})
export class AppModule {}

이제 실제 변환을 담당할 서비스 기능을 정의합니다.

excel.service.ts

import { createReadStream } from 'fs';
import { Injectable } from '@nestjs/common';
import * as csv from 'csv-parser';

@Injectable()
export class ExcelService {
// 받아온 파일 경로를 사용하여 해당 파일을 읽고,
// 'csv-parser' 라이브러리를 이용하여 CSV 데이터를 JSON으로 변환하는 작업을 수행
// Promise를 반환하며, 이 Promise는 CSV 파일의 모든 데이터를 JSON으로 변환한 결과를 담은 배열을 resolve 합니다
    convertCsvToJson(filePath: string): Promise<any[]> {
        const results = [];
    
        return new Promise((resolve, reject) => {
            createReadStream(filePath, { encoding: 'utf-8' })
                .pipe(csv({ separator: '\t' }))  // 탭을 구분자로 사용
                .on('data', (data) => results.push(data))
                .on('end', () => resolve(results))
                .on('error', (error) => reject(error));
        });
    }
}

마지막으로 multer 모듈의 설정을 정의합니다.

multer.options.ts

import { diskStorage } from 'multer';
import { parse } from 'path';
import { v4 as uuid } from 'uuid';

export const multerOptions = {
// 업로드된 파일을 서버의 './uploads' 디렉토리에 저장하도록 설정
  storage: diskStorage({
    destination: './uploads',
    filename: (req, file, cb) => {
      const filename: string =
      // 저장될 파일의 이름을 원래 파일 이름에서 공백을 제거하고 uuid를 추가하여 설정
        parse(file.originalname).name.replace(/\s/g, '') + uuid();
      const extension: string = parse(file.originalname).ext;

      cb(null, `${filename}${extension}`);
    },
  }),
};

이렇게 각 파일들이 함께 작동하여 사용자가 '/upload' 엔드포인트로 CSV 파일을 업로드하면, 서버가 이 파일을 받아서 JSON으로 변환한 뒤 그 결과를 반환한다.

결과 화면