opendata-api
Version:
정책자금, 서민대출 등 공공데이터 API 래퍼
284 lines (281 loc) • 11.9 kB
JavaScript
// src/opendata-api.ts
import axios from "axios";
import { XMLParser } from "fast-xml-parser";
import iconv from "iconv-lite";
import util2 from "util";
// src/opendata-util.ts
import util from "util";
var OpendataUtil = class {
/**
* 현재 한국 기준 연도, 월, 일과 yyyymmdd 형식을 반환합니다.
* @returns {{ year: string, month: string, day: string, yyyymmdd: string }}
*/
static getKoreanDateInfo() {
const now = /* @__PURE__ */ new Date();
const utc = now.getTime() + now.getTimezoneOffset() * 6e4;
const koreaTime = new Date(utc + 9 * 60 * 6e4);
const year = koreaTime.getFullYear().toString();
const month = (koreaTime.getMonth() + 1).toString().padStart(2, "0");
const day = koreaTime.getDate().toString().padStart(2, "0");
return {
year,
month,
day,
yyyymmdd: `${year}${month}${day}`
};
}
static unwrapIfWrapped(payload) {
var _a, _b, _c;
if (payload && typeof payload === "object" && "data" in payload) {
return payload.data;
}
if ((_c = (_b = (_a = payload == null ? void 0 : payload.response) == null ? void 0 : _a.body) == null ? void 0 : _b.items) == null ? void 0 : _c.item) {
return payload.response.body.items.item;
}
return payload;
}
static extractFromXml(xmlObj) {
var _a, _b, _c;
const items = (_c = (_b = (_a = xmlObj == null ? void 0 : xmlObj.response) == null ? void 0 : _a.body) == null ? void 0 : _b.items) == null ? void 0 : _c.item;
if (items)
return items;
throw new Error(util.inspect(xmlObj, { depth: null }));
}
};
var opendata_util_default = OpendataUtil;
// src/opendata-api.ts
var OpenAPIClass = class {
/**
* OpenAPI 인스턴스를 생성합니다.
* @param serviceKey 공공데이터 포털에서 발급받은 서비스 키
*/
constructor(serviceKey) {
this.serviceKey = serviceKey;
}
/**
* 지원사업 공고 정보를 조회합니다.
*
* @param {string} [supt_biz_clsfc] 지원 분야 (선택 사항, 미입력 시 전체 조회)
* @returns {Promise<SupportProjectApiResponse>} 지원사업 공고 정보
*
* @typedef {Object} SupportProjectApiResponse
* @property {number} currentCount 현재 카운트
* @property {SupportProjectApi_SuccessResponseType[]} data 지원사업 공고 목록
*
* @typedef {Object} SupportProjectApi_SuccessResponseType
* @property {string|null} aply_excl_trgt_ctnt 신청 제외 대상 내용
* @property {string|null} aply_mthd_eml_rcpt_istc 이메일 접수 방식
* @property {string|null} aply_mthd_etc_istc 기타 접수 방식
* @property {string|null} aply_mthd_fax_rcpt_istc 팩스 접수 방식
* @property {string|null} aply_mthd_onli_rcpt_istc 온라인 접수 방식
* @property {string|null} aply_mthd_pssr_rcpt_istc 우편 접수 방식
* @property {string|null} aply_mthd_vst_rcpt_istc 방문 접수 방식
* @property {string} aply_trgt 신청 대상
* @property {string} aply_trgt_ctnt 신청 대상 내용
* @property {string|null} biz_aply_url 사업 신청 URL
* @property {string} biz_enyy 사업 경영 연한
* @property {string} biz_gdnc_url 사업 안내 URL
* @property {string} biz_pbanc_nm 사업 공고명
* @property {string} biz_prch_dprt_nm 사업 주관 부서명
* @property {string} biz_trgt_age 사업 대상 연령
* @property {string} detl_pg_url 상세 페이지 URL
* @property {number} id 고유 ID
* @property {string} intg_pbanc_biz_nm 통합공고 사업명
* @property {string} intg_pbanc_yn 통합공고 여부
* @property {string} pbanc_ctnt 공고 내용
* @property {string} pbanc_ntrp_nm 공고 기업명
* @property {string} pbanc_rcpt_bgng_dt 접수 시작일 (YYYYMMDD)
* @property {string} pbanc_rcpt_end_dt 접수 종료일 (YYYYMMDD)
* @property {number} pbanc_sn 공고 일련번호
* @property {string} prch_cnpl_no 연락처
* @property {string|null} prfn_matr 제출 서류
* @property {string} rcrt_prgs_yn 모집 진행 여부
* @property {string} sprv_inst 주관 기관
* @property {string} supt_biz_clsfc 지원사업 분류
* @property {string} supt_regin 지원 지역
*/
async getSupportBizInfoList(supt_biz_clsfc = "") {
const { yyyymmdd } = opendata_util_default.getKoreanDateInfo();
const url = `https://apis.data.go.kr/B552735/kisedKstartupService01/getAnnouncementInformation01?serviceKey=${this.serviceKey}&page=1&perPage=10000&cond[supt_regin::LIKE]=${supt_biz_clsfc}&cond[pbanc_rcpt_bgng_dt::GTE]=${yyyymmdd}&cond[rcrt_prgs_yn::EQ]=Y&returnType=json`;
return this.fetchAndExtract(url);
}
/**
* 통합공고 지원사업 정보를 조회합니다.
*
* @returns {Promise<IntegratedApiResponse>} 통합공고 지원사업 정보
*
* @typedef {Object} IntegratedApiResponse
* @property {number} currentCount 현재 카운트
* @property {IntegratedApi_SuccessResponseType[]} data 지원사업 목록
*
* @typedef {Object} IntegratedApi_SuccessResponseType
* @property {string} biz_category_cd 사업 카테고리 코드
* @property {string} biz_supt_bdgt_info 예산현황 및 지원규모
* @property {string} biz_supt_ctnt 지원 내용
* @property {string} biz_supt_trgt_info 지원 대상 정보
* @property {number} biz_yr 사업 연도
* @property {string} detl_pg_url 상세 페이지 URL
* @property {number} id 고유 ID
* @property {string} supt_biz_chrct 지원사업 특성
* @property {string} supt_biz_intrd_info 지원사업 소개
* @property {string} supt_biz_titl_nm 지원사업 제목
*/
async getIntegratedSupportInfoList() {
const { year } = opendata_util_default.getKoreanDateInfo();
const url = `https://apis.data.go.kr/B552735/kisedKstartupService01/getBusinessInformation01?serviceKey=${this.serviceKey}&page=1&perPage=10000&returnType=json&cond[biz_yr::EQ]=${year}`;
return this.fetchAndExtract(url);
}
/**
* 서민 대출상품한눈에 정보조회 서비스
* @returns {Promise<LoanApiResponse[]>} 서민 대출상품 목록
*
* @typedef {Object} LoanApiResponse
* @property {number} seq
* @property {string} finprdnm 금융상품명
* @property {number} lnlmt 대출한도
* @property {string} lnlmt1000abnml
* @property {string} lnlmt2000abnml
* @property {string} lnlmt3000abnml
* @property {string} lnlmt5000abnml
* @property {string} lnlmt10000abnml
* @property {string} irtCtg 금리 구분
* @property {string} irt 금리
* @property {string} maxtotlntrm 최대 총 대출기간
* @property {string} maxdfrmtrm 최대 거치기간
* @property {string} maxrdpttrm 최대 상환기간
* @property {string} rdptmthd 상환 방법
* @property {string} usge 용도
* @property {string} trgt 대상
* @property {string} instCtg 기관 구분
* @property {string} ofrinstnm 제공 기관명
* @property {string} rsdAreaPamtEqltIstm
* @property {string} suprtgtdtlcond 지원 대상 상세 조건
* @property {string} age 나이 조건
* @property {string} age39blw
* @property {string} age40abnml
* @property {string} age60abnml
* @property {string} incm 소득 조건
* @property {string} incmcndy
* @property {string} incmcndn
* @property {string} incmcnd
* @property {string} rsdarea 거주 지역
* @property {string} crdtsc 신용 점수 조건
* @property {string} crdtsc1
* @property {string} crdtsc2
* @property {string} crdtsc3
* @property {string} crdtsc4
* @property {string} crdtsc5
* @property {string} crdtsc6
* @property {string} crdtsc7
* @property {string} crdtsc8
* @property {string} crdtsc9
* @property {string} crdtsc0
* @property {string} anin
* @property {string} housholdcnt
* @property {string} housar
* @property {string} lntgthous
* @property {string} rfrccnpl 참조 연락처
* @property {string} grninst 보증 기관
* @property {string} jnmthd 접수 방법
* @property {string} rpymdcfe 상환 수수료
* @property {string} lnicdcst 대출 비용
* @property {string} ovitryr 초과 이자율
* @property {string} prftaddirtcond 추가 혜택 조건
* @property {string} etcrefsbjc 기타 참고사항
* @property {string} hdlinst 주관 기관
* @property {string} cnpl 연락처
* @property {string} rltsite 관련 사이트
* @property {string} crdtsc15
* @property {string} crdtsc60
* @property {string} tgtFltr 대상 필터
* @property {string} hdlinstdtlvw 주관 기관 상세 보기
* @property {string} prdCtg 상품 카테고리
* @property {string} prdoprprid 상품 운영 기간
* @property {string} kinfaprdyn 기간 무관 여부
* @property {string} kinfaprdetc 기간 무관 상세
*/
async getAffordableLoanInfoList() {
const url = `https://apis.data.go.kr/B553701/LoanProductSearchingInfo/LoanProductSearchingInfo/getLoanProductSearchingInfo?serviceKey=${this.serviceKey}&pageNo=1&numOfRows=10000&type=json`;
return this._fetchAndExtract(url);
}
/**
* 공통 fetch 및 응답 처리 로직
* @param {string} url 요청 URL
* @returns {Promise<any>} 응답 데이터
*/
async fetchAndExtract(url) {
var _a;
try {
const res = await axios.get(url);
if ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.data) {
return res.data.data;
}
const parser = new XMLParser({
ignoreAttributes: false,
trimValues: true
});
const xmlObj = parser.parse(res.data);
throw new Error(util2.inspect(xmlObj, { depth: null }));
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(`Network Error: ${error.message}`);
}
throw error;
}
}
/**
* 공통 fetch 및 응답 처리 로직 (EUC-KR 대응)
* @param url 요청 URL
* @returns 응답 데이터
*/
async _fetchAndExtract(url) {
var _a, _b, _c, _d;
try {
const res = await axios.get(url, {
responseType: "arraybuffer",
// 원본 바이트
decompress: true,
timeout: 3e4,
headers: { Accept: "application/json, text/plain, */*" }
// transformResponse: [(d) => d], // (선택) axios의 자동 파싱 완전 차단
});
const buf = Buffer.from(res.data);
const contentType = String(res.headers["content-type"] || "").toLowerCase();
let textUtf8 = null;
try {
textUtf8 = buf.toString("utf-8");
return opendata_util_default.unwrapIfWrapped(JSON.parse(textUtf8));
} catch (_) {
}
let textKr = null;
try {
const charset = (((_a = contentType.match(/charset=([^;]+)/i)) == null ? void 0 : _a[1]) || "").toLowerCase();
const guess = charset && charset !== "utf-8" ? charset : "euc-kr";
textKr = iconv.decode(buf, guess);
return opendata_util_default.unwrapIfWrapped(JSON.parse(textKr));
} catch (_) {
}
const parser = new XMLParser({
ignoreAttributes: false,
trimValues: true
});
try {
const xmlObj = parser.parse(textUtf8 != null ? textUtf8 : buf.toString("utf-8"));
return opendata_util_default.extractFromXml(xmlObj);
} catch (_) {
const xmlObj = parser.parse(textKr != null ? textKr : iconv.decode(buf, "euc-kr"));
return opendata_util_default.extractFromXml(xmlObj);
}
} catch (error) {
if ((_c = (_b = axios).isAxiosError) == null ? void 0 : _c.call(_b, error)) {
const status = (_d = error.response) == null ? void 0 : _d.status;
throw new Error(`Network Error${status ? ` (${status})` : ""}: ${error.message}`);
}
throw error;
}
}
};
export {
OpenAPIClass,
opendata_util_default as OpendataUtil
};