Teamsparta Devcamp를 마치며

Devcamp 팀스파르파 부트캠프(정글, 항해, 내일배움캠프) 출신들이 이커머스 쇼핑몰의 핵심 로직을 만들어보는 3주 과정이다. 난 조금 길어져서 10월 2일에 시작해서 10월 27일에 마무리됐다. 팀은 5~6명 정도로 구성되는데 10월의 경우에는 4명의 프론트엔드와 유일한 백엔드인 내가 한 팀이었다. 강의로 혼자 공부, 로그인 및 회원가입 구현, 장바구니 및 결제가 각각 1주일씩 진행된다. 만족할 만한 수준으로 학습이 되지 않거나, 완성도가 떨어지거나 여러 기준으로 충분하지 못하다고 판단되면 다음 단계로 넘어가지 못한다. 백엔드는 NestJS, TypeORM, PostgreSQL, AWS 를 사용한다. 프론트엔드는 Next.js랑 TailwindCSS, Vercel이다. 언어는 Typescript ...

2023년 10월 27일 · 3 분 · 배준수

JWT와 코드 분석

코드는 공개하지 않았습니다! JWT 정의 JSON Web Token의 약자로, 정보를 JSON 개체로 안전하게 전송하기 위한 간결하고 독립적인 방법을 정의한 개방형 표준이다. 상대적으로 크기가 작은 덕분에 URL, POST, 혹은 HTTP 헤더로 빠르게 전송될 수 있다. JWT는 Authorization(권한 허가)에 주로 사용되어, 로그인한 사용자는 이후 Request의 header에 JWT를 포함시켜 보냄으로서 루트, 서비스, 리소스에 대한 접근이 허용된다. 물론 주로 쓰이는 방법일 뿐, JWT가 반드시 Single-Sign-On을 위해 만들어진 기술은 아니다. 등장 배경 기존 authorization은 XML을 기반으로한 SAML(Security Assertion Markup Language) 형식을 이용하였다. 하지만 너무 크고(verbose) 느리다는 단점이 있었다. 따라서 크기가 작아 가볍고 전송이 빠른 JWT를 사용하게 되었다. ...

2023년 10월 12일 · 4 분 · 배준수

NestJS에 대하여

Devcamp 1일차 NestJS Nest는 테스트가 수월하고 확장성이 좋으며 유지보수가 편리한 Node.js 프레임워크 중 하나이다. Typescript Nest는 Typescript를 지원하는 것이 가장 큰 특징이다. 따라서 Interface를 사용할 수 있으며 Static/strong typing을 지원하기 때문에 type에 관해서, 혹은 property나 이름 오류도 코드 작성 단계에서 감지된다. 서버를 매번 실행하는 번거로움 없이 오타나 Type 설정, 디버깅을 할 수 있다는 것은 개발에 들어가는 시간과 노력을 줄여주는 큰 장점이다. 성질 객체지향 프로그래밍, 자료 처리를 수학적 함수의 계산으로 취급하는 FP(Functional Programming), 그리고 비동기적 데이터 흐름의 요소를 갖추고 있다. 기본적으로 Express hTTP 프레임워크를 사용하지만, Fastify를 포함하여 다양한 Node HTTP 프레임워크도 사용할 수 있고, Express에서 지원되는 것들은 Nest에서도 사용할 수 있어서 사용이 편리하다. ...

2023년 10월 11일 · 8 분 · 배준수

App Configuration

Testing Dotenv 터미널에서 npm install @nestjs/config dotenv 는 .env 파일과 일반적인 환경 변수파일을 참조하여 개체를 생성(겹칠시 환경변수 파일 우선)한다. .env 파일은 배포에 포함되선 안된다. (git 에선 gitignore로 commit되지 않도록 해야) 우리는 개발용(배포용) .env 파일과 테스트용 .env 파일 두 개를 만들것이다. root 디렉토리에 .env.tset 와 .env.development 파일 두개를 만들자. 1 2 // .env.development DB_NAME=db.sqlite 1 2 // .env.test DB_NAME=test.sqlite AppModule에 아래와 같이 설정해준다. ...

2023년 10월 10일 · 4 분 · 배준수

Association

Report 다루기 Report는 자동차를 판 사람이 자기가 판매한 가격과 정보를 보고하는 것. 이것을 바탕으로 자신의 중고차 가치를 추정받는 시스템의 정확도를 높일 수 있다. 리포트 Entity 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // reports.entity.ts import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; @Entity() export class Report { @PrimaryGeneratedColumn() id: number; @Column() price: number; @Column() make: string; @Column() model: string; @Column() year: number; @Column() // 판매지역 나타내는 경도 lng: number; @Column() // 판매지역 나타내는 위도 lat: number; @Column() mileage: number; } DTO 생성 컨트롤러를 수정하자 ...

2023년 10월 10일 · 7 분 · 배준수

end to end testing

Testing End to End test 유닛 테스트보다 넓은 범위를 테스트 전체 서비스의 복사본이나 인스턴스 생성 package.json 의 script를 보면 "test:e2e"가 있음. src 폴더 내의 파일 실행 X 서버를 끄고 터미널에서 npm run test:e2e를 입력해보자. 새로운 E2E 테스트 만들기 test 폴더에 auth.e2e-spec.ts 파일을 만들고 app.e2e-spec.ts의 내용을 복사 붙여넣자. 이 후 조금의 수정을 가한다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 // auth.e2e-spec.ts import { Test, TestingModule } from '@nestjs/testing'; import { INestApplication } from '@nestjs/common'; import * as request from 'supertest'; import { AppModule } from './../src/app.module'; describe('Authentication System', () => { let app: INestApplication; beforeEach(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [AppModule], }).compile(); app = moduleFixture.createNestApplication(); await app.init(); }); it('handles a signup request', () => { // 알아보기 쉬운 주석 return request(app.getHttpServer()) .post('/auth/signup') // signup 경로 .send({ email: 'asgkege@akl.com', password: 'qownstn' }) // 무작위 body .expect(201) .then((res) => { // response id, email로 올 것 const { id, email } = res.body; expect(id).toBeDefined(); expect(email).toEqual(email); }); }); }); 터미널에서 npm run test:e2e를 실행하면 문제가 발생한다. 이유를 알아보자. ...

2023년 10월 10일 · 3 분 · 배준수

TypeORM으로 쿼리 작성

TypeORM 쿼리 TypeORM에는 create, save, find, findOne, createQueryBuilder 등 있다. 복잡한 우리의 알고리즘을 위해 createQueryBuilder를 사용하자. 쿼리 설치하기 컨트롤러로 간다. 1 2 3 4 5 // reports.controller.ts @Get() getEstimate(@Query() query: GetEstimateDto) { return this.reportsService.createEstimate(query); } 서비스에 메서드를 추가하자 1 2 3 4 5 6 // reports.service.ts import { GetEstimateDto } from './dtos/get-estimate.dto'; createEstimate(estimateDto: GetEstimateDto) { return this.repo.createQueryBuilder().select('*').getRawMany(); } 우선은 모든 속성을 받도록 쿼리를 작성했다. 서버를 실행하고 API Client에서 만들어 놓은 추정치를 받는 요청을 보내보자. 속성들이 잘 오면 성공. ...

2023년 10월 10일 · 2 분 · 배준수

승인 시스템

기초적인 승인 시스템 제출된 보고서 중 무의미한 데이터를 방지하기 위해 ‘관리자’와 관리자의 승인 개념을 도입한다. 우선은 관리자는 배제한체 승인에 관해서만 구현한다. 우선 report.entity 파일에 속성을 추가하자 1 2 3 // report.entity.ts @Column({ default: false }) approved: boolean; 이후 컨트롤러에 관련 메서드를 추가한다. 1 2 3 // reports.controller.ts @Patch('/:id') approveReport(@Param('id') id: string, @Body() body: ApprovedReportDto) {} reports의 dtos 디렉토리에 새로운 dto를 추가하자. report dto 에도 approved 속성을 추가해야한다. ...

2023년 10월 10일 · 5 분 · 배준수

Authentication, Cookie-session

Authentication Overview 인증 과정의 전체 흐름부터 살펴보자. 어떤 클라이언트가 애플리케이션에 요청하고 우리 서비스에 가입하려고 한다. 요청에는 eamil과 password가 들어있다. 서버는 이메일이 이미 이메일이 사용중인지 확인한다. 유저의 암호를 암호화한다. 새로운 유저 레코드를 저장한다. 요청에 대한 응답으로 유저의 id를 포함하는 쿠키를 되돌려보낸다. 브라우저는 자동적으로 쿠키를 저장하고 이후 클라이언트의 요청에 쿠키를 붙여준다. 유저는 reports를 보낸다. 여기엔 쿠키 포함 되어있고(쿠키 내에는 유저의 id가 포함되어 있다.) report를 위한 정보도 들어있다. 서버는 쿠키의 데이터가 임의로 조작되진 않았는지 확인한다. ...

2023년 10월 9일 · 7 분 · 배준수

Authentication와 Guard

Authentication Custom Decorator 만들기 handler에게 자동으로 현재 로그인한 유저를 알려주는 기능을 만들려고 한다. 우리는 기존의 @Session() 대신 새로운 우리만의 decorator를 만들 것이다. 우리가 만들 CurrentUser Decorator는 2가지가 필요할 것이다. Session Object : 요청한 유저의 id를 알아야 한다. UsersService Instance : 알아낸 id를 가진 사용자를 찾아야 하기 떄문이다. 우리는 Param decorators로 만들어야 한다. 하지만 Param decorators는 DI(종속성 주입) 시스템 외부에 있어서, UsersService 인스턴스를 받을 수 없다. 이 문제를 해결하기 위해 interceptor를 만든다. ...

2023년 10월 9일 · 3 분 · 배준수