signicat-client-ts
Version:
Community TypeScript client for Signicat Authentication REST API with automatic token management
272 lines (271 loc) • 12 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AxiosHttpRequest = void 0;
const axios_1 = __importDefault(require("axios"));
const form_data_1 = __importDefault(require("form-data"));
const ApiError_1 = require("./ApiError");
const BaseHttpRequest_1 = require("./BaseHttpRequest");
const CancelablePromise_1 = require("./CancelablePromise");
const OpenAPI_1 = require("./OpenAPI");
const TokenManager_1 = require("./TokenManager");
let tokenManager = null;
const createTokenManager = () => {
if (OpenAPI_1.SignicatAuth) {
return new TokenManager_1.TokenManager(OpenAPI_1.SignicatAuth);
}
return null;
};
const getTokenManager = () => {
if (!tokenManager && OpenAPI_1.SignicatAuth) {
tokenManager = createTokenManager();
}
return tokenManager;
};
class AxiosHttpRequest extends BaseHttpRequest_1.BaseHttpRequest {
constructor(config) {
super(config);
}
request(options) {
return new CancelablePromise_1.CancelablePromise((resolve, reject, onCancel) => __awaiter(this, void 0, void 0, function* () {
var _a;
try {
const tm = getTokenManager();
// 자동 토큰 관리가 설정되어 있고 토큰이 명시적으로 제공되지 않은 경우
if (tm && !this.config.TOKEN) {
// 요청 전에 토큰을 가져옴
const token = yield tm.getToken();
const mutableOptions = Object.assign({}, options);
mutableOptions.headers = Object.assign(Object.assign({}, mutableOptions.headers), { Authorization: `Bearer ${token}` });
options = mutableOptions;
}
const response = yield this.sendRequest(options, onCancel);
resolve(response.data);
}
catch (error) {
const axiosError = error;
// 토큰 관련 오류(401)인 경우 토큰을 갱신하고 재시도
if (((_a = axiosError.response) === null || _a === void 0 ? void 0 : _a.status) === 401 && getTokenManager()) {
try {
// 토큰 강제 갱신
yield getTokenManager().refreshToken();
// 새 토큰으로 요청 재시도
const token = yield getTokenManager().getToken();
const mutableOptions = Object.assign({}, options);
mutableOptions.headers = Object.assign(Object.assign({}, mutableOptions.headers), { Authorization: `Bearer ${token}` });
const response = yield this.sendRequest(mutableOptions, onCancel);
resolve(response.data);
}
catch (retryError) {
reject(this.handleError(retryError, options));
}
}
else {
reject(this.handleError(error, options));
}
}
}));
}
sendRequest(options, onCancel) {
return __awaiter(this, void 0, void 0, function* () {
const url = `${this.config.BASE}${options.url}`;
const formData = this.getFormData(options);
const body = this.getRequestBody(options);
const headers = yield this.getHeaders(options);
const cancelToken = options.cancelToken;
const config = Object.assign({ url, data: body !== null && body !== void 0 ? body : formData, method: options.method, headers, params: options.query, timeout: options.timeout, withCredentials: this.config.WITH_CREDENTIALS, cancelToken }, (options.responseType && { responseType: options.responseType }));
if (options.mediaType === "application/json") {
config.data = JSON.stringify(config.data);
}
// Cancel handler 등록
if (onCancel && cancelToken) {
onCancel(() => {
if (cancelToken.cancel) {
cancelToken.cancel("Request cancelled");
}
});
}
return axios_1.default.request(config);
});
}
handleError(error, options) {
var _a;
if (axios_1.default.isCancel(error)) {
return new CancelablePromise_1.CancelError(error.message || "Request was cancelled");
}
const axiosError = error;
if (axiosError.response) {
return new ApiError_1.ApiError(options, {
url: ((_a = axiosError.response.config) === null || _a === void 0 ? void 0 : _a.url) || "",
ok: false,
status: axiosError.response.status,
statusText: axiosError.response.statusText,
body: axiosError.response.data,
}, axiosError.message);
}
return new ApiError_1.ApiError(options, {
url: "",
ok: false,
status: 0,
statusText: axiosError.message,
body: null,
}, axiosError.message);
}
getFormData(options) {
if (options.formData) {
const formData = new form_data_1.default();
for (const key in options.formData) {
if (options.formData[key] !== undefined && options.formData[key] !== null) {
const value = options.formData[key];
if (value instanceof Array) {
for (const item of value) {
formData.append(key, item);
}
}
else {
formData.append(key, value);
}
}
}
return formData;
}
return undefined;
}
getRequestBody(options) {
if (options.mediaType === "application/x-www-form-urlencoded" && options.body) {
return new URLSearchParams(options.body).toString();
}
return options.body;
}
getHeaders(options) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
const token = yield this.getToken();
const username = yield this.getUsername();
const password = yield this.getPassword();
const additionalHeaders = yield this.getAdditionalHeaders();
const headers = Object.assign(Object.assign({ Accept: (_a = options.mediaType) !== null && _a !== void 0 ? _a : "application/json" }, additionalHeaders), options.headers);
if (options.mediaType) {
headers["Content-Type"] = options.mediaType;
}
if (token) {
headers.Authorization = `Bearer ${token}`;
}
if (username && password) {
const credentials = btoa(`${username}:${password}`);
headers.Authorization = `Basic ${credentials}`;
}
return headers;
});
}
getToken() {
return __awaiter(this, void 0, void 0, function* () {
const token = this.config.TOKEN;
if (!token) {
return undefined;
}
if (typeof token === "function") {
return yield token({});
}
return token;
});
}
getUsername() {
return __awaiter(this, void 0, void 0, function* () {
const username = this.config.USERNAME;
if (!username) {
return undefined;
}
if (typeof username === "function") {
return yield username({});
}
return username;
});
}
getPassword() {
return __awaiter(this, void 0, void 0, function* () {
const password = this.config.PASSWORD;
if (!password) {
return undefined;
}
if (typeof password === "function") {
return yield password({});
}
return password;
});
}
getAdditionalHeaders() {
return __awaiter(this, void 0, void 0, function* () {
const headers = this.config.HEADERS;
if (!headers) {
return {};
}
if (typeof headers === "function") {
return yield headers({});
}
return headers;
});
}
request_(options) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
try {
const tm = getTokenManager();
// 자동 토큰 관리가 설정되어 있고 토큰이 명시적으로 제공되지 않은 경우
if (tm && !this.config.TOKEN) {
const token = yield tm.getToken();
const mutableOptions = Object.assign({}, options);
mutableOptions.headers = Object.assign(Object.assign({}, mutableOptions.headers), { Authorization: `Bearer ${token}` });
options = mutableOptions;
}
const cancelToken = options.cancelToken;
const config = Object.assign({ url: `${this.config.BASE}${options.url}`, method: options.method, headers: yield this.getHeaders(options), params: options.query, timeout: options.timeout, withCredentials: this.config.WITH_CREDENTIALS, cancelToken }, (options.responseType && { responseType: options.responseType }));
const response = yield axios_1.default.request(config);
const result = {
url: response.config.url || "",
ok: response.status >= 200 && response.status < 300,
status: response.status,
statusText: response.statusText,
body: response.data,
};
return result;
}
catch (error) {
if (axios_1.default.isCancel(error)) {
const cancelError = error;
throw new CancelablePromise_1.CancelError(cancelError.message);
}
const axiosError = error;
if (axiosError.response) {
const result = {
url: ((_a = axiosError.response.config) === null || _a === void 0 ? void 0 : _a.url) || "",
ok: false,
status: axiosError.response.status,
statusText: axiosError.response.statusText,
body: axiosError.response.data,
};
throw new ApiError_1.ApiError(options, result, axiosError.message);
}
throw new ApiError_1.ApiError(options, {
url: "",
ok: false,
status: 0,
statusText: error.message,
body: null,
}, error.message);
}
});
}
}
exports.AxiosHttpRequest = AxiosHttpRequest;