holidays-kr
Version:
data.go.kr 데이터 기반 공휴일 수집
88 lines (72 loc) • 2.31 kB
text/typescript
import axios from "axios";
import { XMLParser, XMLValidator } from "fast-xml-parser";
import { config, ENDPOINT } from "./config";
import { zerofill, addDay } from "./utils";
import { HolidayItem, ResponseData } from "./types";
const getHolidaysByMonth = async (
year: number,
month: number
): Promise<HolidayItem[]> => {
const { data } = await axios.get(ENDPOINT, {
params: {
solYear: year,
solMonth: zerofill(month, 2),
ServiceKey: config.serviceKey,
},
});
if (!XMLValidator.validate(data)) {
throw new Error("XML 파싱에 실패앴습니다.");
}
const parser = new XMLParser();
const parsedXml = parser.parse(data);
if (
parsedXml.OpenAPI_ServiceResponse &&
parsedXml.OpenAPI_ServiceResponse.cmmMsgHeader
) {
const header = parsedXml.OpenAPI_ServiceResponse.cmmMsgHeader;
throw new Error(
header.returnAuthMsg || header.errMsg || header.returnReasonCode
);
}
if (!data.response?.body?.items?.item) {
throw new Error("응답받은 포멧이 정상적이지 않습니다.");
}
const responseData: ResponseData = data;
const {
items: { item },
} = responseData.response.body;
const holidays: HolidayItem[] = [];
const itemList = Array.isArray(item) ? item : [item];
itemList.forEach((item) => {
addDay(item, holidays);
});
return holidays;
};
export const getHolidaysByMonthCount = async (
year: number,
month: number,
monthCount: number = 1
): Promise<HolidayItem[]> => {
const promiseList = [];
if (monthCount > 13) {
throw Error(
"최대 12개월을 넘을 수 없습니다. 어차피 실제 입력된 데이터도 1년을 넘지 않습니다."
);
}
for (let i = 0; i < monthCount; i++) {
const targetYear = year + Math.floor((month + i - 1) / 12);
const targetMonth = (month + i) % 12 || 12;
// 한번에 빨리 요청하면 막히기 때문에 100ms 간격으로 요청
promiseList.push(
new Promise<HolidayItem[]>((resolve, reject) => {
setTimeout(() => {
getHolidaysByMonth(targetYear, targetMonth)
.then((r) => resolve(r))
.catch((r) => reject(r));
}, 100 * Math.max(i - 10, 0));
})
);
}
const result = await Promise.all(promiseList);
return result.flat();
};