앞으로의 목표 👍


  1. javascript 능력 및 고난도 알고리즘 풀이 능력
  2. Nest, Graphql등 최신 기술 스택 활용 능력
  3. 기초 미니프로젝트 포트폴리오
  4. 로그인, 결제기반 심화프로젝트 포트폴리오
  5. 배포를 위한 네트워크 및 CI/CD 배포자동화 능력
  6. 120% 백엔드 개발 지식

오늘부터 꾸준히 해야할 일 👍


  • 영타실력 늘리기
  • 단축키 사용 익숙해지기
  • 코드리딩 실력 키우기
  • 데일리 퀴즈
  • 포트폴리오 작성
  • 독스에 친숙해지기
  • MDN 보는 연습하기

오늘의 수업 👍



📝 API 만들기 전 필수 지식


▷ 1. 스프레드 연산자

▷ 2. REST 파라미터

▷ 3. 객체의 KEY 특징

▷ 4. 클래스(Class)와 의존성주입(DI)

▷ 5. private readonly 역할

▷ 6. 타입스크립트-기본타입

▷ 7. 타입스크립트-데코레이터(@)

▷ 8. 타입스크립트-유틸리티타입

▷ 9. 그래프큐엘 Code-First (schema.gql 자동 생성)

📝 DB 연동하여 API 만들기 실습


  • @mutation @get에는 화살표함수를 지원하지 않는다.

  • express에서는 바로 나가지만 (async await 필수)

  • nestjs에서는 기다리는 공간이 있어서 기다렸다가 나간다. (async await 자유)

📝 가격 데이터 검증 실습


class-validator 설치

$ yarn add class-validator
$ yarn add class-transformer
  • create-product.input
import { Field, InputType, Int } from '@nestjs/graphql';
import { Min } from 'class-validator';

@InputType()
export class CreateProductInput {
  @Field(() => String)
  name: string;

  @Field(() => String)
  description: string;

  @Min(0) // 최소값 설정 => 0보다 작은 수는 못들어온다.
  @Field(() => Int)
  price: number;
}
  • main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe()); // ValidationPipe를 연결
  await app.listen(3000);
}
bootstrap();
  • Pipe는 데이터가 오고가는 흐름에 있어서 데이터 검증과 필터링을 해주는 역할을 합니다.
  • 위의 설정들을 해줌으로써, price 가격에 0보다 작은 값을 넣게되면 API 요청이 이루어지지 않습니다.

📝 수정하기 API와 수정 전 검증 실습


백엔드 개발자는 항상 수정과 삭제는 민감하게 반응해야한다.

▶ update-product.input.ts

@InputType()
export class UpdateProductInput extends PartialType(CreateProductInput) {
  // 아래 내용들을 상속 받음
  //   @Field(() => String)
  //   name?: string;
  //
  //   @Field(() => String)
  //   description?: string;
  //
  //   @Field(() => Int)
  //   price?: number;
}
  • PickType(CreateProductInput, ['name', 'price']) => 뽑기
  • OmitType(CreateProductInput, ['description']) => 빼기
  • PartialType(CreateProductInput) => 물엄표(있어도 되고, 없어도 됨) 만들기

▶ products.service.ts에 추가

  async update({ productId, updateProductInput }) {
    const product = await this.productsRepository.findOne({
      where: { id: productId },
    });

    // this.productsRepository.create() // 등록X, DB접속이랑 관련 없음 ( 객체를 따로 만들고 싶을 때 사용 )
    // this.productsRepository.insert() // 등록 방법. (등록한 결과를 객체로 못 돌려받음)
    // this.productsRepository.update({ 조건 }, { 수정할 내용 }) // 수정방법 (수정한 결과를 객체로 못 돌려받음)
    // this.productsRepository.save({}) // 등록(id가 없으면)/수정(id가 있으면) 하고 조회해서 가져온다. (등록/수정한 결과를 객체로 돌려받음)

    const result = this.productsRepository.save({
      id: productId,
      ...product, // 수정 후, 수정되지 않ㅇ은 다른 결과값까지 모두 객체로 돌려 받고 싶을 때
      ...updateProductInput, // Key가 같아도 스프레드 연산자를 사용하면 아래있는 게 위에 것을 덮어씌운다.
      // 아래 3줄이 위 1줄과 같다.(스프레드 연산자)
      // name: updateProductInput.name,
      // description: updateProductInput.description,
      // price: updateProductInput.price,
    });
    return result;
  }
}

▷ 유지보수성 올리기

  async update({ productId, updateProductInput }) {
    const product = await this.findOne(productId); // 위에 있는 API 활용

    // this.productsRepository.create() // 등록X, DB접속이랑 관련 없음 ( 객체를 따로 만들고 싶을 때 사용 )
    // this.productsRepository.insert() // 등록 방법. (등록한 결과를 객체로 못 돌려받음)
    // this.productsRepository.update({ 조건 }, { 수정할 내용 }) // 수정방법 (수정한 결과를 객체로 못 돌려받음)
    // this.productsRepository.save({}) // 등록(id가 없으면)/수정(id가 있으면) 하고 조회해서 가져온다. (등록/수정한 결과를 객체로 돌려받음)

    const result = this.productsRepository.save({
      id: productId,
      ...product, // 수정 후, 수정되지 않ㅇ은 다른 결과값까지 모두 객체로 돌려 받고 싶을 때
      ...updateProductInput, // Key가 같아도 스프레드 연산자를 사용하면 아래있는 게 위에 것을 덮어씌운다.
      // 아래 3줄이 위 1줄과 같다.(스프레드 연산자)
      // name: updateProductInput.name,
      // description: updateProductInput.description,
      // price: updateProductInput.price,
    });
    return result;

▶ products.resolver.ts에 추가

  @Mutation()
  updateProduct(
    @Args('productId') productId: string,
    @Args('updateProductInput') updateProductInput: UpdateProductInput,
  ) {
    return this.productsService.update({ productId, updateProductInput });
  }
  • 에러 -> 코드를 잘못작성한 것

  • 버그 -> 잘 작동되지만 의도되지 않은 것(제일 수정하기 힘듬)

  • 예외 -> 예기치 못한 상황

  • 상태코드 -> 정답은 없다, 프론트엔드 개발자에게 알려주기 쉽게 하기 위해서 사용한다.

    • 200 번대 : 성공 상태 코드
    • 400 번대 : 프론트에서 요청을 잘못했을 때 발생하는 에러 상태 코드
    • 500 번대 : 백엔드 서버에서 문제가 생겼을 때 발생하는 에러 상태코드

📝 예외 처리 실습


▷ HttpExceptionFilter

  • NestJS 에서 제공해주는 ExceptionFilter

  • http-exception.filter.ts

import { Catch, ExceptionFilter, HttpException } from '@nestjs/common';

@Catch(HttpException)
class HttpExceptionFilter implements ExceptionFilter {
  // 에러가 나면 여기로 날아온다.

  catch(exception: HttpException) {
    const status = exception.getStatus();
    const message = exception.message;

    console.log('===========================');
    console.log('예외가 발생했어요!!');
    console.log('예외내용:', message);
    console.log('예외코드:', status);
    console.log('===========================');
  }
}
  • @Catch(HttpException) => 에러 관련된 내용이 들어가 있음을 NestJS 에게 알려주기 위한 데코레이터를 사용했습니다.
  • catch => Exception 상황 발생시 비즈니스 로직에 try ~ catch 문이 없더라도 자동으로 에러가 catch 문으로 들어옵니다.
    • exception => HttpException : HttpException type 으로 정의해줬습니다.
  • implements ExceptionFilter => class 에서 타입을 정의 해주기 위해 implements 사용했습니다.

오늘의 마무리 👍



  • 복습
  • github 공부
  • 블로그 포스팅
  • 데일리 퀴즈
  • 알고리즘 문제 풀기

항상 겸손한 자세로 배우면서 성장하자, 할 수 있다!! 💪


출처 : 코드캠프

profile
개발자 블로그 / 항상 겸손한 자세로 배우면서 성장하자 할 수 있다!

0개의 댓글