http ํต์
http ํต์
์ด์ ๋๋น์ ์ฐ๊ฒฐํ์ผ๋ ๋๋น์ ์ ์ฅํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผ๊ฒ ์ฃ ?
์ ๋ ๊ณต๊ณต๋ฐ์ดํฐํฌํธ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์์ ์ ๋๋ค.
์ฌ๋ฌ๋ถ๋ค๋ ๊ณต๊ณต๋ฐ์ดํฐํฌํธ์ ๋ค์ด๊ฐ์ ์์ ์ด ์ํ๋ api๋ฅผ ์ฐพ์๋ณด๊ณ ์ฌ์ฉํ์๋ฉด ๋ ๊ฒ ๊ฐ์ต๋๋ค.
http ํต์ ์ ํ๊ธฐ ์ํด์ ํจํค์ง๋ฅผ ์ค์นํด์ผ ํฉ๋๋ค.
ํจํค์ง ์ค์น ๋ฐฉ๋ฒ์
npm install ํจํค์ง์ด๋ฆ์ด๋ ๊ฒ ์ด๋ฃจ์ด์ง๋๋ค. ์ ๋ axios๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์นํ ์์ ์ ๋๋ค.
nestjs ํํ์ด์ง๊ฐ๋ฉด nest/axios ๋ผ๊ณ ์์ต๋๋ค. ๊ทธ๊ฑธ ์ค์นํ๋ฉด ๋ฉ๋๋ค.
npm i --save @nestjs/axios axios
์ด๋ ๊ฒ ํ๋ค์ ๋ด๊ฐ http ํต์ ๋น์ง๋์ค๋ก์ง์ ์์ฑํ ์๋น์คํ์ผ์ httpservice ์ํดํธ, ์๋จ ๋ชจ๋์์ http๋ชจ๋์ ์ํดํธ์์ ๋ฃ์ผ์๋ฉด ๋ฉ๋๋ค.
์๋น์ค์๋ ์์ ํด์ค๋๋ค.
์ด์ api ํจ์๋ฅผ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
import { Injectable, Logger } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
@Injectable()
export class FranchiseApiService {
private readonly logger = new Logger(FranchiseApiService.name);
constructor(private httpService: HttpService) {}
async fetchingFranchiseApi({ year, pageNo = 1, numOfRows = 100 }: { year: string; pageNo?: number; numOfRows?: number }) {
const options = {
method: 'GET',
url: 'https://franchise.ftc.go.kr/api/search.do',
params: {
type: 'list',
yr: year,
serviceKey: '๋น๊ณต๊ฐํค', // ์๋ณธ ํค ์ฌ์ฉ (+ ๊ทธ๋๋ก)
pageNo,
numOfRows
},
headers: {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Accept-Language': 'ko-KR,ko;q=0.9,en;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Cache-Control': 'max-age=0',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'none',
'Sec-Fetch-User': '?1',
'Upgrade-Insecure-Requests': '1'
}
};
try {
this.logger.log(`API ์์ฒญ ์์: year=${year}, page=${pageNo}, rows=${numOfRows}`);
const response = await this.httpService.axiosRef.get(options.url, {
params: options.params,
headers: options.headers
});
this.logger.log(`ํ๋์ฐจ์ด์ฆ API ์๋ต ์ฑ๊ณต: status=${response.status}`);
// XML ๋ฐ์ดํฐ ํ์ธ์ฉ ๋ก๊ทธ
if (response.data.includes('<totalCount>')) {
const totalCount = response.data.match(/<totalCount>(\d+)<\/totalCount>/)?.[1];
this.logger.log(`์ด ๋ฐ์ดํฐ ๊ฐ์: ${totalCount}`);
}
return response.data;
} catch (error) {
this.logger.error(`ํ๋์ฐจ์ด์ฆ API ์์ฒญ ์คํจ: ${error.message}`);
throw new Error(`ํ๋์ฐจ์ด์ฆ API ์์ฒญ ์คํจ: ${error.message}`);
}
}
}ํ๋ผ๋ฏธํฐ์ ๊ฒฝ์ฐ ๋ด๊ฐ ์ฌ์ฉํ๋ api์์ ์์ฒญํ๋ ํ๋ผ๋ฏธํฐ๋ฅผ ์์ฑํ๋ ๊ฒ์ด๊ณ
ํค๋์ ๊ฒฝ์ฐ๋ ๋์ ์ ์ ํ๊ฒฝ์ ํ์ํ ์ ์๊ณ , ํค๋ ๋ฃ์ ์ ์์ต๋๋ค. ํน์ ์น์ฌ์ดํธ๋ ํฌ๋กค๋ง์ผ๋ก ์ธํด ๋ด ์ ๊ทผ์ ๋ง์ ์ ์์ด์
ํค๋์ ์ผ๋ฐ ์นํ์ด์ง ์ฌ์ฉ์๋ผ๊ณ ๋ณด์ฌ์ง๊ธฐ ์ํด ์ ๋ ๊ฒ ํด๋๋ฅผ ์์ฑํ์ต๋๋ค. ๊ทธ๋ผ ์ด์ api๋ฅผ ํ ์คํธ ํด๋ด์ผ๊ฒ ์ฃ ?
nest ๋ช ๋ น์ด๋ฅผ ํตํด ์ปจํธ๋กค๋ฌ๋ฅผ ์์ฑ ํฉ๋๋ค.
import { FranchiseApiService } from './franchise-api.service';
import { Controller, Get } from '@nestjs/common';
@Controller('franchise-api')
export class FranchiseApiController {
constructor(private readonly franchiseApiService: FranchiseApiService) {}
@Get()
async franchiseApiTest() {
const data = await this.franchiseApiService.fetchingFranchiseApi({ year: '2023', pageNo: 1, numOfRows: 10 });
return { message: 'Franchise API data', data: data };
}
}
์ด๋ ๊ฒ ํ ์คํธํ ์ ์๋ api๋ฅผ ์ฝ๋ฉํ๊ณ ํ ์คํธ๋ ํฐ๋ฏธ๋ ๋๋ ํฌ์คํธ๋งจ ํ๋ก๊ทธ๋จ, ์น์ฌ์ดํธ์์ ํ ์ ์์ต๋๋ค.
์ ๋ ํฌ์คํธ๋งจ ํ๋ก๊ทธ๋จ์ผ๋ก ํ ์คํธ ํด๋ณด๊ฒ ์ต๋๋ค.
์ด๋ฐ์์ผ๋ก http status๊ฐ 200 ok๊ฐ ๋์ค๋ฉด์ ๋ฐ์ดํฐ๊ฐ ์ ์์ ์ผ๋ก ๋์ค๋ฉด api ์์ฒญ์ด ์ฑ๊ณตํ ๊ฒ์ ๋๋ค.
