Nest 2주차

세현·2022년 11월 24일
0

mongoose 연결할때 오류가 나서 한참 고민했는데 알고보니 패키지를 다른 위치에 설치했었다. ㅠㅠㅠ

프로젝트 진행중에 기억해볼점

dto

우선은 ,dto

프론트엔드에서 데이터를 받아오고 생성하는 과정에서 이 데이터는 body에서 값이 넘어오게 된다. 하지만 우리가 필요한 값이 안 넘어오면 할 수 있는 것이 없다. 이런 상황에서 사용할 수 있는 것이 DTO

1주차에서 DTO는 body에서 넘어오는 값들의 형식등을 정의해준다고 말하고 몽구스의 스키마와 유사하다고 말했는데

import { IsEmail, IsNotEmpty, IsString } from 'class-validator';

export class CatRequestDto {
  @IsEmail()
  @IsNotEmpty()
  email: string;

  @IsString()
  @IsNotEmpty()
  password: string;

  @IsString()
  @IsNotEmpty()
  name: string;
}

다시보니 스키마와 유사한거 같다. 이렇게 CatRequestDto에 받아올 데이터의 형식을 지정해준다.

다시 서비스로 돌아가보자.

@Post()
  async signUp(@Body() body: CatRequestDto) {
    return await this.catsService.signUp(body);
  }

이렇게 받아오는 body의 형식을 CatRequestDto로 설정하면 body 데이터가 CatRequestDto와 형식이 다르다면 오류를 반환한다.

create

async signUp(body: CatRequestDto) {
    const { email, name, password } = body;
    const isCatExist = await this.catModel.exists({ email });

    if (isCatExist) {
      throw new UnauthorizedException('해당하는 고양이는 이미 존재합니다');
    }
    const hashedPassword = await bcrypt.hash(password, 10);

    const cat = await this.catModel.create({
      email,
      name,
      password: hashedPassword,
    });
    return cat.readOnlyData;
  }

위에서 exists는 모델에 email이 있는지 확인하는 함수로 이를 통해 유효성 검사를 한다고 생각하면 좋다.

비밀번호는 bcrypt로 암호화

아래의 readOnlyData는 가상의 출력 화면으로 반환 데이터에서 password가리기 위해 사용, schema에서 설정해준다.

CatSchema.virtual('readOnlyData').get(function (this: Cat) {
  return {
    id: this.id,
    email: this.email,
    name: this.name,
  };
});

repository 패턴

프로그램의 구조를 보면 service <-> data store 이렇게 이어져 있는데, 여러개의 service를 이용하는 경우 다른 service를 참조하는 일들이 생긴다. 다른 service들을 참고하다보면 순환 참조가 일어나게 되는데 이를 해결하기 위해 service와 data store 사이에 repository라는 레이어를 추가해서 해결한다.

이 친구도 service의 기능을 이용하기에 model의 providers에 추가를 해줘야 한다.

로그인 서비스

  • 세션과 쿠키
  • jwt
  • token

jwt = json web token
jwt는 3가지의 정보로 이루어져 있다. header, payload, signature이다.

Header : base64 인코딩 토큰의 타입과 알고리즘
Payload : base64 인코딩 데이터
Signature : Header/Payload를 조합하고 비밀키로 서명한 후, base64로 인코딩

과정

프론트엔드에서 로그인 요청 => {email,password} => 백엔드의 Login API => secret key를 통해 jwt 토큰 생성

인증

프론트에서 백으로 요청을 보낼 때 헤더에 jwt 토큰을 같이 보낸다.
=> JWT guard -> JWT strategy에서 secret key를 가지고 디코딩 -> 해당 user를 request.user에 저장

https://docs.nestjs.com/security/authentication

파일 업로드

npm i -D @types/multer

해당 명령문으로 필요한 패키지를 설치를 진행한다.

@Post('upload')
@UseInterceptors(FileInterceptor('file'))
uploadFile(@UploadedFile() file: Express.Multer.File) {
  console.log(file);
}

서버에는 이렇게 설정해서 파일들을 받을 수 있다.

그리고 해당 모듈에 가서

MulterModule.register({
  dest: './upload',
});

를 추가해준다. 여기서 dest는 저장되는 경로를 의미한다.

API들 마다 서로 다른 경로에 저장을 해주는 것이 좋다.
그렇기 때문에 utils 폴더에 multer.options.ts파일에

export const multerOptions = (folder: string) => {
 const result: MulterOptions = {
 	storage: storage(folder),
 };
 return result;
};

folder를 인자로 받는다. 아래의 storage는 folder 이름을 인자로 받아서 해당 폴더를 만들어주는 함수이다.

const storage = (folder: string): multer.StorageEngine => {
	createFolder(folder);
	return multer.diskStorage({
 		destination(req, file, cb) {
 		//* 어디에 저장할 지
 		const folderName = path.join(__dirname, '..', `uploads/${folder}`);
 		cb(null, folderName);
 	},
 	filename(req, file, cb) {
 	//* 어떤 이름으로 올릴 지
 	const ext = path.extname(file.originalname);
 		const fileName = `${path.basename(
			file.originalname,
			ext,
		)}${Date.now()}${ext}`;

		cb(null, fileName);
 		},
	});
};

이 코드를 통해서 어디에 저장할지를 지정해주고, 어떤 이름으로 파일을 올릴지 설정해주는 함수이다.
이렇게 multer의 option을 설정하면 다시 controller로 돌아가보자.

@Post('upload')
@UseInterceptors(FileInterceptor('image',10,multerOptions("cats"))
uploadFile(@UploadedFile() file: Express.Multer.File) {
  console.log(file);
}

@UseInterceptors의 인자를 보면 원래는 'files'였지만 우리는 이미지를 올리거기 때문이 'image'로 설정한다. 하고 multerOptions의 'cats'를 인자로 보냄으로써 해당 폴더를 만들게 한다.

profile
안녕하세요

0개의 댓글