NestJS 帶你飛! 시리즈 번역 21# HTTP Module

2023. 6. 18. 00:35개발 문서 번역/NestJS

728x90
이 포스팅은 「NestJS 기초실무 가이드 : 강력하고 쉬운 Node.js 웹 프레임워크로 웹사이트 만들기」
(서명: NestJS 基礎必學實務指南:使用強大且易擴展的 Node.js 框架打造網頁應用程式)
책이 출간되었습니다.

 

개발을 하다보면 Third-Party API를 연동해야 할 때가 많습니다.

(ex: 아임포트, sendbird 등..)

이때 Third-Party API에서 관련 SDK를 제공하지 않는다면 반드시 HTTP Request를 통해 그에 해당하는 자료들을 받아와야 합니다.

일찍이 node.js개발자는 request를 통해 구현 하였습니다.
하지만 이 라이브러리는 이미 지원이 중단된 라이브러리이기에 이를 대체하기 위한 node-fetchaxios가 탄생하였습니다.

Nest 또한 HTTP Module을 내장하고 있습니다. 이 모듈은 axios를 기반으로 패키징된 모듈인데요.

Nest 개발자가 어떤 라이브러리를 사용해야 할지에 대한 고민도 해결해주었네요. 바로 사용해봅시다!

주의: Nest 8 이후 버전에서는 HTTP Module을 @nestjs/axios라는 패키지로 독립시켰습니다.
8버전 이후의 NestJS를 사용하신다면 npm install @nestjs/axios를 통해 따로 설치해주어야 합니다.
원문 예제에서는 8버전 이전을 사용하였지만,
번역본의 예제에서는 8버전 이후의 독립된 모듈을 사용하도록 하겠습니다.
(2023년 6월 기준 Nest의 최신버전은 10버전입니다.)

 

HTTP Module 사용하기

HTTP Module의 class 이름은 HttpModule이며 HttpService라는 Service를 제공합니다.

이 서비스는 HTTP 요청을 처리하기 위해 axios 메서드를 제공하며, Observable의 형태로 작동합니다.

주의: axios에 대한 메서드들이 궁금하시다면 공식사이트를 참고해주세요.

 

app.module.ts를 예로 들어보겠습니다. HttpModule을 import 해보겠습니다.

import { HttpModule } from '@nestjs/axios';
import {  Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [HttpModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

JSONPlaceholder를 Third-Party API로 가져와 todos의 자원을 사용하겠습니다.

해당 데이터 구조를 interface의 형태로 src/common/models 폴더 내의 todo.model.ts라는 이름으로 저장하겠습니다.

export interface Todo {
  userId: number;
  id: number;
  title: string;
  completed: boolean;
}

app.service.ts의 내용을 getTodos 메서드가 todos의 자원을 얻어올 수 있도록 수정하겠습니다.

주의: Agent 문제로 인해 httpsAgentrejectUnauthorizedfalse로 설정해야만 API가 정상적으로 작동합니다.
import { HttpService } from '@nestjs/axios';
import { Injectable } from '@nestjs/common';
import { Agent } from 'https';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { Todo } from './common/models/todo.model';

@Injectable()
export class AppService {

  constructor(
    private readonly http: HttpService
  ) {}

  getTodos(): Observable<Todo> {
    const httpsAgent = new Agent({ rejectUnauthorized: false });
    return this.http.get('https://jsonplaceholder.typicode.com/todos', { httpsAgent }).pipe(
      map((res) => res.data)
    );
  }

}

 

다음은 app.controller.ts입니다. getTodos 안에 AppServicegetTodos를 가져오도록 작성해줍니다.

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get('/todos')
  getTodos() {
    return this.appService.getTodos();
  }

}

 

http://127.0.0.1:3000/todos 에 get 요청을 보내놓으면 아래와 같은 결과를 확인할 수 있습니다.

 

axios 기본 설정

앞서 언급한 예제에서는 JSONPlaceholder의 todos 리소스에 접근할 때 Agent 문제가 발생할 수 있습니다.

이와 같은 문제가 여러개의 API에서 발생하며 매번 같은 코드를 반복작성 하고 싶지 않은 경우

HttpModuleregister 메서드를 사용하여 기본 값을 구성할 수 있습니다.

해당 기본값은 HttpService의 각 메서드 options와 동일한 구성 요소들을 가질 수 있습니다.

 

보다 자세한 설명은 공식 사이트를 참고해주세요.

 

아래는 app.module.ts의 예제입니다. Agent 구성을 기본 값을 설정해보겠습니다.

import { HttpModule } from '@nestjs/axios';
import {  Module } from '@nestjs/common';
import { Agent } from 'https';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    HttpModule.register({
      httpsAgent: new Agent({ rejectUnauthorized: false })
    })
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

 

이어서 app.service.ts를 수정하겠습니다. Agent 설정 했던 부분을 삭제시켜줍니다.

import { HttpService } from '@nestjs/axios';
import { Injectable } from '@nestjs/common';
import { Agent } from 'https';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { Todo } from './common/models/todo.model';
@Injectable()
export class AppService {

  constructor(
    private readonly http: HttpService
  ) {}

  getTodos(): Observable<Todo> {
    return this.http.get('https://jsonplaceholder.typicode.com/todos').pipe(
      map((res) => res.data)
    );
  }

}

 

http://127.0.0.1:3000/todos에 접속하면 todos의 결과를 성공적으로 받아온걸 확인할 수 있습니다.

 

환경변수 사용

HttpModuleregisterAsync 메서드를 제공합니다.
이 메서드를 통해 의존성이 있는 Provider를 추가할 수 있으며 팩토리 함수를 사용하여 해당 값을 HttpModule에 주입할 수 있습니다. 해당 원리를 사용하여 ConfigService를 주입한 후에 구성 하고싶은 기본값을 전달하도록 하겠습니다.

간단한 예제를 만들어 사용해보겠습니다.

 

프로젝트 경로에 .env파일에 다음과 같은 환경 변수를 추가해줍니다.

HTTP_TIMEOUT=3000

app.module.ts를 수정하여 registerAsync에서 ConfigModule을 import하고

injectsConfigService를 전달한 후

마지막으로 useFactory에서 ConfigService를 주입하도록 설정하겠습니다.

import { HttpModule } from '@nestjs/axios';
import {  Module } from '@nestjs/common';
import { Agent } from 'https';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import {ConfigModule, ConfigService} from '@nestjs/config';
@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true
    }),
    HttpModule.registerAsync({
      imports: [ConfigModule],
      useFactory: (config: ConfigService) => ({
        httpsAgent: new Agent({ rejectUnauthorized: false }),
        timeout: config.get('HTTP_TIMEOUT')
      }),
      inject: [
        ConfigService
      ]
    })
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

이렇게 하면 환경변수를 HttpModule에 전달하여 기본값을 구성하게되면

HttpModule의 설정을 프로젝트 환경에 맞게 유연하게 구성할 수 있습니다.

 

마치며

Nest는 Http Request와 관련있는 기능들을 전부 내장 모듈로 제공하기 때문에 무척 편리합니다.

직접 HttpService에 주입하면 바로 사용할 수 있고, 어떤 라이브러리를 사용해야 하는지 생각하지 않아도 될 뿐더러

라이브러리를 Nest 모듈로 패키징하지 않아도 되니까요.

 

아래는 오늘 포스팅의 요약본입니다.

 

1. HttpModule는 내장 모듈로, HttpService를 주입해 axios 메서드를 사용할 수 있게끔 해줍니다.

2. HttpModuleregister를 통해 기본값을 설정할 수 있습니다.

3. HttpModuleregisterAsync를 통해 주입된 Provider의 값을 가져와 기본값을 구성할 수 있습니다.