저번엔 Controller 와 Provider 등을 알아본다고 별로 한게 없는데, 이번엔 광고 컨텐츠 등록 API 를 한번 건드려보겠습니다.
DB 는 좀 나중에 연동하기로하고, 컨텐츠를 등록하면 Slack 으로 알람을 보내는 모듈을 만들어보겠습니다.
뭔가 사이드부터 하는 것 같다면 그게 맞습니다..
export class CreateAdDto {}
일전에 생성했던 리소스대로면 AdsController 의 create, update 메서드는 CreateAdDto 타입의 파라미터를 받게 되어있습니다.
DTO (Data Transfer Object) 는 굳이 적지 않아도 아시다시피 프로세스나 레이어 사이에서 데이터를 전송하는 객체입니다.
직렬화, 역직렬화 로직 또는 단순한 getter setter 정도의 메서드만 가질 뿐 어떠한 비즈니스 로직도 담지 않습니다.
NestJS 에선 클라이언트 - 서버 사이에서 요청 / 응답을 전송하는 객체를 DTO 라고 볼 수 있으며, NestJS 에선 DTO 가 구현되어 있어
클라이언트의 요청과 함께 들어오는 데이터인 페이로드를 쉽게 다룰 수 있습니다.
지금은 위 코드처럼 CreateAdDto 가 비어있는데, 일단 이 부분부터 정의를 해보겠습니다.
export class CreateAdDto {
adType: string;
title: string;
thumbnail: string;
content: string;
country: string;
}
뭐 추후에 이것저것 들어갈수도 있겠지만, 일단 광고라는걸 등록하는데는 이정도 정보면 충분할 것 같습니다.
광고타입, 광고제목, 썸네일, 광고내용, 국가 정도의 정보를 받게 되어있습니다. 타입에만 ad 가 붙은건 typescript 에서 type 키워드와
구분하기 위함일 뿐 별 의미는 없습니다. 일부는 나중에 enum 으로 바뀌어야할 필요도 있지만, 일단 string 으로 갑니다.
@Controller('ads')
export class AdsController {
constructor(private readonly adsService: AdsService) {}
@Post()
create(@Body() createAdDto: CreateAdDto) {
console.info(
createAdDto.adType,
createAdDto.title,
createAdDto.thumbnail,
createAdDto.content,
createAdDto.country,
);
return this.adsService.create(createAdDto);
}
...
}
제대로 동작하는지 확인차 console.info 로 확인해볼까 합니다.
Postman 을 사용해 위처럼 요청을 보내면, 정상적으로 페이로드를 받는걸 확인할 수 있습니다.
DTO 는 여기까지만 일단 확인하고, Slack 서비스를 별도 모듈로 만들어보겠습니다.
> nest g mo Slack
> nest g s Slack
Slack 서비스는 외부로부터 HTTP 요청을 받는게 아니므로 nest-cli 를 통해 모듈과 서비스만 생성해줍니다.
// src/slack/slack.service.ts
import { Injectable } from '@nestjs/common';
import axios from 'axios';
@Injectable()
export class SlackService {
private token: string;
private channel: string;
constructor() {
this.token = 'XXX';
this.channel = 'XXX';
}
async send(adType: string, title: string, country: string) {
await axios({
method: 'post',
url: 'https://slack.com/api/chat.postMessage',
data: {
channel: this.channel,
attachments: [
{
color: '#999999',
title: '광고가 등록되었습니다.',
text: `${adType} - ${title} - ${country}`,
},
],
},
headers: {
'Content-Type': 'application/json;charset=UTF-8',
Authorization: `Bearer ${this.token}`,
},
});
}
}
생성한 SlackService 를 저는 위와 같이 만들어봤습니다. 위에서 깜빡했는데 HTTP 요청에 사용하려고 axios 모듈을 추가했습니다.
충분히 나중에 확장될 수 있지만 우선 이 서비스는 광고가 등록되었을때만 사용된다라고 가정하고, slack api 를 사용해 채널로
slack message 를 보냅니다.
token, channel, url 이 지금은 하드코딩 되어있는데 이후 ConfigService 를 사용하도록 변경할 예정입니다.
// src/slack/slack.module.ts
import { Module } from '@nestjs/common';
import { SlackService } from './slack.service';
@Module({
providers: [SlackService],
exports: [SlackService],
})
export class SlackModule {}
아까 nest-cli 로 생성한 SlackModule 에는 SlackService 가 providers 에만 등록되어있고 exports 가 없을 것입니다.
우리는 이 SlackService 를 AdsService 에 주입해 사용해야하므로 exports 에 추가해줍니다.
// src/ads/ads.module.ts
import { Module } from '@nestjs/common';
import { AdsService } from './ads.service';
import { AdsController } from './ads.controller';
import { SlackModule } from '../slack/slack.module';
@Module({
imports: [SlackModule],
controllers: [AdsController],
providers: [AdsService],
})
export class AdsModule {}
SlackModule 에서 exports 해준것만으론 AdsModule context 에서 SlackService 를 사용할 수 없습니다.
SlackModule 을 AdsModule 에 imports 해줍니다.
...
@Injectable()
export class AdsService {
constructor(private readonly slackService: SlackService) {}
async create(createAdDto: CreateAdDto) {
const { adType, title, country } = createAdDto;
await this.slackService.send(adType, title, country);
return 'This action adds a new ad';
}
...
}
이제 SlackService 를 AdsService 에 주입하고, create 시 SlackService 의 send 메서드를 호출해줍니다.
진짜 생성은 건드리지도 않고 이것부터 하고 있다는게 제가 보기에도 이상하긴 하네요. 하고싶은거부터 하다보니..
위에서 Postman 으로 동일한 요청을 보낸 후 slack 을 확인하면 위와 같은 메세지가 온 것을 볼 수 있습니다.
아래는 현재까지의 디렉토리 구조입니다.
너무 간단하긴하지만, Slack 부분만 모듈화를 해보았습니다. 일반적으로 모듈이라는 건 작게보면 정의상 하나의 함수도 모듈이라고 할 수 있겠습니다만, 여러 컴퍼넌트를 조합해 그보다는 좀 더 큰 작업을 수행할 수 있는 단위입니다.
애초에 Node.JS 부터 이런 모듈화에 특화되어있고, 하나의 서비스 또는 서버들은 여러 모듈이 모여 만들어지게 되죠.
NestJS 앱은 하나의 루트 모듈이 존재하고 (일반적으론 app.module.ts) 이 루트 모듈들은 여러 다른 모듈들로 구성됩니다.
지금 작성하고 있는 서버도 app.module.ts 라는 루트 모듈을 ads.module.ts 와 slack.module.ts 가 구성하고 있죠.
어떤 기준으로 모듈을 나누느냐는 정해진 게 없지만 기본적으로 응집도를 높인다는 개념을 베이스로 모듈화를 가져가면 좋을 것입니다.
이렇게 나눈 모듈 자체가 점점 커지면 MSA 관점에서 하나의 마이크로서비스가 될 수도 있겠죠. 작은 모듈이라고 분리안하고 그냥 모듈 하나에 다 때려넣다간 상당한 똥이 되어있는것을 목도하게 될 것 같습니다.
'Backend > NestJS' 카테고리의 다른 글
NestJS - 대충 서비스 만들어보기 (6) (0) | 2023.04.15 |
---|---|
NestJS - 대충 서비스 만들어보기 (5) (0) | 2023.04.08 |
NestJS - 대충 서비스 만들어보기 (3) (0) | 2023.03.19 |
NestJS - 대충 서비스 만들어보기 (2) (0) | 2023.03.04 |
NestJS - 대충 서비스 만들어보기 (1) (0) | 2023.02.25 |