naver-api-exchange-rate
Version:
129 lines (110 loc) • 3.63 kB
JavaScript
import { URLSearchParams } from 'node:url';
export const CURRENCIES = {
USD: 'USD',
EUR: 'EUR',
JPY: 'JPY',
CNY: 'CNY',
GBP: 'GBP',
KRW: 'KRW',
AUD: 'AUD',
CAD: 'CAD',
CHF: 'CHF',
HKD: 'HKD',
SGD: 'SGD',
THB: 'THB',
};
const DEFAULTS = {
bank: 'keb',
amount: 1,
from: CURRENCIES.USD,
to: CURRENCIES.KRW,
unit: 'standardUnit',
direction: 'down',
pkid: 141,
};
function validateOptions(options) {
if (options.amount !== undefined) {
const amount = Number(options.amount);
if (isNaN(amount) || amount <= 0) {
throw new Error('금액은 0보다 큰 숫자여야 합니다.');
}
}
if (options.from && (typeof options.from !== 'string' || !/^[A-Z]{3}$/.test(options.from))) {
throw new Error(`잘못된 통화 코드 형식입니다: ${options.from}. 3자리 대문자여야 합니다 (예: USD, EUR, JPY)`);
}
if (options.to && (typeof options.to !== 'string' || !/^[A-Z]{3}$/.test(options.to))) {
throw new Error(`잘못된 통화 코드 형식입니다: ${options.to}. 3자리 대문자여야 합니다 (예: USD, EUR, JPY)`);
}
}
export async function convert(options = {}) {
try {
validateOptions(options);
const opts = { ...DEFAULTS, ...options };
const q = encodeURIComponent('환율');
const params = new URLSearchParams({
key: 'calculator',
pkid: opts.pkid,
q,
where: 'm',
u1: opts.bank,
u2: opts.amount,
u3: opts.from,
u4: opts.to,
u6: opts.unit,
u7: '0',
u8: opts.direction,
});
const url = `https://m.search.naver.com/p/csearch/content/qapirender.nhn?${params.toString()}`;
let res;
try {
res = await fetch(url);
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
}
} catch (error) {
throw new Error(`네트워크 오류가 발생했습니다: ${error.message}`);
}
const body = await res.text();
let rate;
try {
const jsonData = typeof body === 'string' ? JSON.parse(body) : body;
if (jsonData.country && jsonData.country.length >= 2) {
const fromValue = parseFloat(jsonData.country[0].value.replace(/,/g, ''));
const toValue = parseFloat(jsonData.country[1].value.replace(/,/g, ''));
rate = toValue / fromValue;
}
} catch (jsonError) {
const match = body.match(/<span class="rate _rate">([\d,.]+)<\/span>/);
if (!match) {
throw new Error('환율 정보를 파싱할 수 없습니다.');
}
rate = parseFloat(match[1].replace(/,/g, ''));
}
if (isNaN(rate) || rate <= 0) {
throw new Error('올바르지 않은 환율 값입니다');
}
return {
from: opts.from,
to: opts.to,
amount: opts.amount,
rate,
result: Math.round(rate * opts.amount * 100) / 100,
raw: body,
};
} catch (error) {
if (error.response) {
throw new Error(`네이버 서버 오류 (${error.response.status}): ${error.response.statusText}`);
}
throw error;
}
}
export function getSupportedCurrencies() {
return Object.values(CURRENCIES);
}
export const exchange = convert;
export const usdToKrw = (amount = 1) => convert({ amount, from: 'USD', to: 'KRW' });
export const krwToUsd = (amount = 1) => convert({ amount, from: 'KRW', to: 'USD' });
export const eurToKrw = (amount = 1) => convert({ amount, from: 'EUR', to: 'KRW' });
export const jpyToKrw = (amount = 1) => convert({ amount, from: 'JPY', to: 'KRW' });
export const cnyToKrw = (amount = 1) => convert({ amount, from: 'CNY', to: 'KRW' });
export default exchange;