2025. 2. 23. 21:37ㆍNodejs
지난 글에서는 서버리스 프레임워크를 사용하여 프로젝트를 생성하고, 간단한 샘플 코드를 작성하여 실행해 보았습니다. 이제부터 본격적으로 기능을 구현해 나가겠습니다. 이번 글에서는 RSS 피드를 가져오는 부분에 대해 살펴보겠습니다.
- 프로젝트 설정
- RSS 피드 가져오기
- 슬랙에 메시지 전송하기
- 중복 알림 방지하기
- 배포
1. 레포지토리 목록 관리
먼저, RSS 피드를 가져올 레포지토리 목록을 준비해야 합니다. 단순히 코드에서 변수로 선언하여 관리할 수도 있지만, 더 편리하게 관리하기 위해 CSV 파일을 활용하려고 합니다. src/data 폴더 아래에 github-repo.csv 파일을 생성하고, 아래와 같이 작성합니다.
[src/data/github-repo.csv]
packageName,sourceUrl,slackChannelId
PNPM,https://github.com/pnpm/pnpm/releases.atom,C0123L3210J
Node.js,https://github.com/nodejs/node/releases.atom,C1234L56S7J
- packageName : 패키지명입니다. 메시지나 에러에서 식별하기 위해서 사용합니다.
- sourceUrl : 릴리즈 알림을 받을 GitHub 레포지토리 주소에 release.atom을 추가하면 됩니다.
- slackChannelId : 알림을 받을 슬랙 채널의 ID입니다.
2. 레포지토리 목록 가져오기
이제 github-repo.csv 파일을 읽어서 Javascript 객체로 변환해야 합니다. 이를 위해 csv-parser 라이브러리를 사용합니다.
$ pnpm add csv-parser
src/service 폴더 아래에 github-release-notification.ts 파일을 생성하고, GitHubReleaseNotificationService 클래스를 선언합니다. 이 클래스에서 주요 비즈니스 로직을 관리하게 될 것입니다. 주요 로직의 흐름은 run 함수에 정리해 두었으며, 이제 하나씩 구현해 나가도록 하겠습니다.
[src/service/github-release-notification.ts]
export class GitHubReleaseNotificationService {
async run(): Promise<void> {
/**
* TODO
* RSS 피드 조회
* 중복 알림 제거
* 알림 전송
* 알림 내역 저장
*/
}
}
CSV 파일을 읽어 Javascript 객체로 변환하는 loadFeedSources 함수를 추가하고, 이를 run 함수에서 활용하도록 수정합니다.
[src/service/github-release-notification.ts]
import * as fs from 'fs';
import csvParser from 'csv-parser';
export type FeedSource = {
packageName: string;
sourceUrl: string;
slackChannelId: string;
}
export class GitHubReleaseNotificationService {
private async loadFeedSources(): Promise<FeedSource[]> {
const feedSources: FeedSource[] = [];
const stream = fs.createReadStream("src/data/github-repo.csv", "utf-8").pipe(csvParser());
for await (const data of stream) {
feedSources.push(data);
}
return feedSources;
}
async run(): Promise<void> {
const feedSources = await this.loadFeedSources();
for await (const feedSource of feedSources) {
/**
* TODO
* RSS 피드 조회
* 중복 알림 제거
* 알림 전송
* 알림 내역 저장
*/
}
}
}
3. RSS 피드 조회
RSS 피드를 조회하기 위해 rss-parser 라이브러리를 사용합니다. rss-parser는 RSS 피드를 파싱하여 Javascript 객체로 변환하는 라이브러리입니다.
$ pnpm add rss-parser
이 라이브러리는 여러 서비스에서 반복적으로 사용되므로, 별도의 서비스로 분리하여 싱글톤 패턴으로 관리하겠습니다. src/service 폴더 아래에 rss-parse.service.ts 를 만들고 아래와 같이 코드를 작성합니다.
[src/service/rss-parse.service.ts]
import RSSParser from 'rss-parser';
export const rssParser = new RSSParser();
rss-parser가 반환하는 값은 모든 속성이 옵셔널이므로, 누락된 값이 없는지 검사하는 함수를 추가합니다. src/lib 폴더 아래에 validator.ts 파일을 추가하고 아래와 같이 작성합니다.
[src/lib/validator.ts]
export const isFullyFilled = <T extends Record<string, unknown>>(
obj: T
): obj is Required<T> => {
return Object.values(obj).every((value) => !isNil(value));
};
이제 feedSource의 sourceUrl을 통해 RSS 피드를 조회하고, Javascript 객체로 반환하는 parseRSS 함수를 추가하고, 이를 run 함수에 활용하도록 수정합니다.
[src/service/github-release-notification.ts]
...
// add
import { rssParser } from './rss-parse.service';
import { isFullyFilled } from '../lib/validator';
...
// add
export type FeedItem = {
id: string;
version: string;
link: string;
date: string;
}
export class GitHubReleaseNotificationService {
...
// add
private async parseRSS(sourceUrl: string): Promise<FeedItem[]> {
const feed = await rssParser.parseURL(sourceUrl);
const items = feed.items.reduce<FeedItem[]>((acc, cur) => {
// feed.items 배열의 요소들은 모든 속성이 옵셔널이므로,
// 유효한 데이터만 처리할 수 있도록 검증합니다.
if (isFullyFilled(cur)) {
const { title, link, isoDate } = cur;
acc.push({
id: link,
version: title,
link,
date: isoDate
});
}
return acc;
}, []);
return items;
}
async run(): Promise<void> {
const feedSources = await this.loadFeedSources();
for await (const feedSource of feedSources) {
const { packageName, sourceUrl, slackChannelId } = feedSource;
// RSS 피드 조회
const items = await this.parseRSS(sourceUrl);
// 테스트를 위해 items를 출력해보겠습니다.
console.log(items);
// 중복 알림 제거
// 알림 전송
// 알림 내역 저장
}
}
}
지금까지 작성한 코드를 테스트하기 위해서 src/handler.ts 파일과 serverless.yml 파일의 functions 부분을 아래와 같이 수정합니다.
[src/handler.ts]
import { GitHubReleaseNotificationService } from "./service/github-release-notification.service";
export const notifyAll = () => {
const gitHubReleaseNotificationService = new GitHubReleaseNotificationService();
await gitHubReleaseNotificationService.run();
}
[serverless.yml]
...
functions:
notifyAll:
handler: src/handler.notifyAll
events:
- schedule: rate(1 hour)
이제 sls invoke 명령어를 사용하여 배포한 함수를 실행할 수 있습니다. 아래 명령어를 실행하면, 가져온 RSS 피드가 출력되는 것을 확인할 수 있습니다. 참고로, sls invoke local은 배포된 함수가 아닌 로컬 환경에서 작성한 함수를 실행하는 명령어입니다.
$ sls invoke local --function notifyAll
다음 글에서는
이번 글에서는 rss-parser 라이브러리를 활용하여 RSS 피드를 조회하고, 가져온 데이터를 원하는 형태로 변환하는 과정을 다뤘습니다. 또한, 여러 개의 RSS 피드 소스를 효율적으로 관리하기 위해 CSV 파일을 만들고, csv-parser를 활용하여 해당 파일을 읽어오는 기능을 구현했습니다. 다음 글에서는 가져온 데이터를 슬랙으로 전송하는 기능을 구현해 보겠습니다.
2025.02.15 - [Nodejs] - 슬랙으로 RSS 알림 보내기 (1) - 개요
2025.02.19 - [Nodejs] - 슬랙으로 RSS 알림 보내기 (2) - 프로젝트 설정
2025.02.23 - [Nodejs] - 슬랙으로 RSS 알림 보내기 (3) - RSS 피드 가져오기
2025.02.26 - [Nodejs] - 슬랙으로 RSS 알림 보내기 (4) - 슬랙에 메시지 전송하기
'Nodejs' 카테고리의 다른 글
슬랙으로 RSS 알림 보내기 (5) - 중복 알림 방지하기 (0) | 2025.03.01 |
---|---|
슬랙으로 RSS 알림 보내기 (4) - 슬랙에 메시지 전송하기 (0) | 2025.02.26 |
슬랙으로 RSS 알림 보내기 (2) - 프로젝트 설정 (0) | 2025.02.19 |
슬랙으로 RSS 알림 보내기 (1) - 개요 (0) | 2025.02.15 |
모듈 시스템 - 타입스크립트에서 ESM 사용하기 (0) | 2025.01.02 |