maplestory-openapi
Version:
This JavaScript library enables the use of the MapleStory OpenAPI of Nexon.
138 lines (135 loc) • 4.71 kB
JavaScript
import axios, { AxiosError } from 'axios';
import dayjs from 'dayjs';
import timezone from '../../../node_modules/dayjs/plugin/timezone.js';
import utc from '../../../node_modules/dayjs/plugin/utc.js';
import { MapleStoryApiError } from './mapleStoryApiError.js';
dayjs.extend(timezone);
dayjs.extend(utc);
/**
* MapleStory OpenAPI client.
*/
class MapleStoryApi {
apiKey;
client;
static BASE_URL = 'https://open.api.nexon.com/';
static DEFAULT_TIMEOUT = 5000;
get timeout() {
return this.client.defaults.timeout;
}
set timeout(value) {
this.client.defaults.timeout = value;
}
constructor(apiKey) {
this.apiKey = apiKey;
this.client = axios.create({
baseURL: MapleStoryApi.BASE_URL,
timeout: MapleStoryApi.DEFAULT_TIMEOUT,
headers: {
'x-nxopen-api-key': this.apiKey,
},
});
this.client.interceptors.response.use((response) => response, (error) => {
if (error instanceof AxiosError) {
const errorBody = error.response
.data;
throw new MapleStoryApiError(errorBody);
}
throw error;
});
}
//#endregion
/**
* API 서버의 데이터 갱신 시간에 따라 데이터가 조회 가능한 최신 날짜를 반환합니다.
*
* @param options
*/
getProperDefaultDateOptions(options) {
const { hour, minute, dateOffset } = options;
const nowInTimezone = dayjs().utcOffset(this.timezoneOffset);
const updateDate = dayjs().utcOffset(this.timezoneOffset).hour(hour).minute(minute);
let adjustedDate;
if (nowInTimezone.isAfter(updateDate)) {
adjustedDate = nowInTimezone;
}
else {
adjustedDate = nowInTimezone.subtract(1, 'day');
}
adjustedDate = adjustedDate.subtract(dateOffset ?? 0, 'day');
return {
year: adjustedDate.year(),
month: adjustedDate.month() + 1,
day: adjustedDate.date(),
};
}
;
/**
* 날짜 정보를 API 서버에서 요구하는 포맷으로 변환합니다.
*
* @param dateOptions 조회 하려는 날짜
* @param minDateOptions API 호출 가능한 최소 날짜
*/
toDateString(dateOptions, minDateOptions) {
const convert = (dateOptions) => {
let year;
let month;
let day;
let d;
if (dateOptions instanceof Date) {
d = dayjs(dateOptions).utcOffset(this.timezoneOffset);
year = d.year();
month = d.month() + 1;
day = d.date();
}
else {
year = dateOptions.year;
month = dateOptions.month;
day = dateOptions.day;
d = dayjs(`${year}-${month}-${day}`).utcOffset(this.timezoneOffset);
}
return {
year,
month,
day,
d,
};
};
const { year, month, day, d } = convert(dateOptions);
const str = d.format('YYYY-MM-DD');
if (minDateOptions) {
const { year: minYear, month: minMonth, day: minDay, } = convert(minDateOptions);
if (year < minYear ||
(year === minYear && month < minMonth) ||
(year === minYear && month === minMonth && day < minDay)) {
throw new Error(`You can only retrieve data after ${dayjs(`${minYear}-${minMonth}-${minDay}`).format('YYYY-MM-DD')}.`);
}
}
return str;
}
;
/**
* API 응답 데이터가 비어있는지 확인 합니다.<br/>
* API 요청 시 날짜에 해당하는 데이터가 없을 경우 date 필드만 값이 존재하는 상황을 검증할 때 사용 합니다.<br/>
* 일반적으로 API 지원 시작일과 캐릭터 생성일 사이의 날짜를 조회할 때 발생 합니다.
* @example
* ```
* isEmptyResponse({ date: '2024-01-01', popularity: null }) // true
* isEmptyResponse({ date: '2024-01-01', popularity: 10 }) // false
* ```
*/
isEmptyResponse(body) {
for (const [key, value] of Object.entries(body)) {
if (key === 'date') {
continue;
}
if (value === null || value === undefined) {
continue;
}
if (Array.isArray(value) && value.length === 0) {
continue;
}
return false;
}
return true;
}
}
export { MapleStoryApi };