외부호출 기능(rest API)
This commit is contained in:
@@ -35,6 +35,8 @@ import multiConnectionRoutes from "./routes/multiConnectionRoutes";
|
||||
import dbTypeCategoryRoutes from "./routes/dbTypeCategoryRoutes";
|
||||
import ddlRoutes from "./routes/ddlRoutes";
|
||||
import entityReferenceRoutes from "./routes/entityReferenceRoutes";
|
||||
import externalCallRoutes from "./routes/externalCallRoutes";
|
||||
import externalCallConfigRoutes from "./routes/externalCallConfigRoutes";
|
||||
// import collectionRoutes from "./routes/collectionRoutes"; // 임시 주석
|
||||
// import batchRoutes from "./routes/batchRoutes"; // 임시 주석
|
||||
// import userRoutes from './routes/userRoutes';
|
||||
@@ -88,7 +90,7 @@ app.use(
|
||||
// Rate Limiting (개발 환경에서는 완화)
|
||||
const limiter = rateLimit({
|
||||
windowMs: 1 * 60 * 1000, // 1분
|
||||
max: config.nodeEnv === "development" ? 10000 : 100, // 개발환경에서는 10000으로 증가, 운영환경에서는 100
|
||||
max: config.nodeEnv === "development" ? 10000 : 1000, // 개발환경에서는 10000으로 증가, 운영환경에서는 100
|
||||
message: {
|
||||
error: "너무 많은 요청이 발생했습니다. 잠시 후 다시 시도해주세요.",
|
||||
},
|
||||
@@ -142,6 +144,8 @@ app.use("/api/multi-connection", multiConnectionRoutes);
|
||||
app.use("/api/db-type-categories", dbTypeCategoryRoutes);
|
||||
app.use("/api/ddl", ddlRoutes);
|
||||
app.use("/api/entity-reference", entityReferenceRoutes);
|
||||
app.use("/api/external-calls", externalCallRoutes);
|
||||
app.use("/api/external-call-configs", externalCallConfigRoutes);
|
||||
// app.use("/api/collections", collectionRoutes); // 임시 주석
|
||||
// app.use("/api/batch", batchRoutes); // 임시 주석
|
||||
// app.use('/api/users', userRoutes);
|
||||
|
||||
@@ -180,10 +180,57 @@ export class ExternalCallService {
|
||||
body = this.processTemplate(body, templateData);
|
||||
}
|
||||
|
||||
// 기본 헤더 준비
|
||||
const headers = { ...(settings.headers || {}) };
|
||||
|
||||
// 인증 정보 처리
|
||||
if (settings.authentication) {
|
||||
switch (settings.authentication.type) {
|
||||
case "api-key":
|
||||
if (settings.authentication.apiKey) {
|
||||
headers["X-API-Key"] = settings.authentication.apiKey;
|
||||
}
|
||||
break;
|
||||
case "basic":
|
||||
if (
|
||||
settings.authentication.username &&
|
||||
settings.authentication.password
|
||||
) {
|
||||
const credentials = Buffer.from(
|
||||
`${settings.authentication.username}:${settings.authentication.password}`
|
||||
).toString("base64");
|
||||
headers["Authorization"] = `Basic ${credentials}`;
|
||||
}
|
||||
break;
|
||||
case "bearer":
|
||||
if (settings.authentication.token) {
|
||||
headers["Authorization"] =
|
||||
`Bearer ${settings.authentication.token}`;
|
||||
}
|
||||
break;
|
||||
case "custom":
|
||||
if (
|
||||
settings.authentication.headerName &&
|
||||
settings.authentication.headerValue
|
||||
) {
|
||||
headers[settings.authentication.headerName] =
|
||||
settings.authentication.headerValue;
|
||||
}
|
||||
break;
|
||||
// 'none' 타입은 아무것도 하지 않음
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`🔐 [ExternalCallService] 인증 처리 완료:`, {
|
||||
authType: settings.authentication?.type || "none",
|
||||
hasAuthHeader: !!headers["Authorization"],
|
||||
headers: Object.keys(headers),
|
||||
});
|
||||
|
||||
return await this.makeHttpRequest({
|
||||
url: settings.url,
|
||||
method: settings.method,
|
||||
headers: settings.headers || {},
|
||||
headers: headers,
|
||||
body: body,
|
||||
timeout: settings.timeout || this.DEFAULT_TIMEOUT,
|
||||
});
|
||||
@@ -213,17 +260,36 @@ export class ExternalCallService {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), options.timeout);
|
||||
|
||||
const response = await fetch(options.url, {
|
||||
// GET, HEAD 메서드는 body를 가질 수 없음
|
||||
const method = options.method.toUpperCase();
|
||||
const requestOptions: RequestInit = {
|
||||
method: options.method,
|
||||
headers: options.headers,
|
||||
body: options.body,
|
||||
signal: controller.signal,
|
||||
});
|
||||
};
|
||||
|
||||
// GET, HEAD 메서드가 아닌 경우에만 body 추가
|
||||
if (method !== "GET" && method !== "HEAD" && options.body) {
|
||||
requestOptions.body = options.body;
|
||||
}
|
||||
|
||||
const response = await fetch(options.url, requestOptions);
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
const responseText = await response.text();
|
||||
|
||||
// 디버깅을 위한 로그 추가
|
||||
console.log(`🔍 [ExternalCallService] HTTP 응답:`, {
|
||||
url: options.url,
|
||||
method: options.method,
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
ok: response.ok,
|
||||
headers: Object.fromEntries(response.headers.entries()),
|
||||
responseText: responseText.substring(0, 500), // 처음 500자만 로그
|
||||
});
|
||||
|
||||
return {
|
||||
success: response.ok,
|
||||
statusCode: response.status,
|
||||
|
||||
@@ -53,14 +53,26 @@ export interface DiscordSettings extends ExternalCallConfig {
|
||||
avatarUrl?: string;
|
||||
}
|
||||
|
||||
// 인증 설정 타입
|
||||
export interface AuthenticationSettings {
|
||||
type: "none" | "api-key" | "basic" | "bearer" | "custom";
|
||||
apiKey?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
token?: string;
|
||||
headerName?: string;
|
||||
headerValue?: string;
|
||||
}
|
||||
|
||||
// 일반 REST API 설정
|
||||
export interface GenericApiSettings extends ExternalCallConfig {
|
||||
callType: "rest-api";
|
||||
apiType: "generic";
|
||||
url: string;
|
||||
method: "GET" | "POST" | "PUT" | "DELETE";
|
||||
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD";
|
||||
headers?: Record<string, string>;
|
||||
body?: string;
|
||||
authentication?: AuthenticationSettings;
|
||||
}
|
||||
|
||||
// 이메일 설정
|
||||
|
||||
Reference in New Issue
Block a user