응답유형별 서버 실주소 처리 개선
eapim-admin CI / build (push) Has been cancelled

- 저장본에 sentinel 유지 및 편집기 사용 시 실주소로 치환
- 응답유형별 서버 실주소 계산 유틸 함수 추가
This commit is contained in:
Rinjae
2026-08-11 16:56:33 +09:00
parent 347cca2d7c
commit c19c12df70
+45 -17
View File
@@ -29,6 +29,10 @@
// (enricher 는 oauth·api_key 를 모두 apiKey-in-header 로 모델링하므로 scheme.type 만으로 구분 불가)
var djbAuthType = '';
// 저장 스펙의 서버 자리표시자. 포탈이 제공 시점에 응답유형(sample/mock/gw)별 실주소로 치환한다.
// (포탈 DjbTestbedSpecServerRewriter.SERVER_SENTINEL 과 동일 문자열 — 양쪽을 같이 바꿔야 한다)
const SERVER_SENTINEL = 'http://swagger-server-url';
// ============================================================
// 2. 유틸
// ============================================================
@@ -108,7 +112,13 @@
// ============================================================
// 3. OpenAPI 스펙 빌더 (state.data → OpenAPI 3.1 객체)
// ============================================================
function buildOpenApiSpec() {
/**
* state.data → OpenAPI 3.1 객체.
*
* @param resolveHost true 면 응답유형별 실주소를 서버에 부착(편집기 미리보기·다운로드용),
* false/생략이면 서버를 sentinel 로 남긴다(저장본 — 포탈이 제공 시점에 치환).
*/
function buildOpenApiSpec(resolveHost) {
const d = state.data;
syncResponseExamplesFromSchema(); // 응답 예제 = 응답 정보(스키마·예제값) 파생 — 저장/미리보기 일관
const spec = {
@@ -195,21 +205,19 @@
// - gw : djb.gateway.base-url (PortalProperty) → [gw호스트 + 어댑터경로 + 경로]
// - mock : Mock Server URL(전체 URL) → [mock URL 그대로] (어댑터/오퍼레이션 경로 미부착)
// - 그 외 : 호스트 없음 → [어댑터경로 + 경로]
var _rt = (d.portal && d.portal.responseType) || 'sample';
var _host;
var _pathKey = op.path.value;
if (_rt === 'gw') {
_host = (window.DJB_CTX && window.DJB_CTX.gwAddress) || 'http://127.0.0.1:39310';
} else if (_rt === 'mock') {
// Mock 은 전체 호출 URL. origin=서버, pathname(+query)=경로로 분해해 경로가 뒤에 덧붙지 않도록 한다.
var _mk = splitFullUrl((d.portal && d.portal.mockUrl) || '');
_host = _mk.origin;
_pathKey = _mk.path;
//
// 단 이 실주소 부착은 "미리보기/다운로드" 표현에만 적용한다(resolveHost=true).
// 저장본은 서버를 sentinel 로 남겨 환경 독립을 유지하고, 포탈이 제공 시점에 응답유형별 실주소로
// 치환한다(DjbTestbedSpecServerRewriter). 저장본에 실주소를 굳히면 포탈의 재치환이 무력화되고
// 저장 환경(dev)의 GW 주소가 다른 환경까지 따라간다.
if (resolveHost) {
var _resolved = resolveSpecServer();
if (_resolved.host) spec.servers = [{ url: _resolved.host }];
spec.paths[_resolved.path] = { [op.method.value.toLowerCase()]: operation };
} else {
_host = '';
spec.servers = [{ url: SERVER_SENTINEL }];
spec.paths[op.path.value] = { [op.method.value.toLowerCase()]: operation };
}
if (_host) spec.servers = [{ url: _host }];
spec.paths[_pathKey] = { [op.method.value.toLowerCase()]: operation };
// 보안 스킴
d.securitySchemes.forEach(s => {
@@ -981,6 +989,24 @@
}
}
// 응답유형별 실주소 { host, path }. 편집기 미리보기·다운로드에서만 사용(저장본은 sentinel).
// - gw : DJB_CTX.gwAddress + [어댑터경로 + 경로]
// - mock : Mock Server URL 을 origin/path 로 분해 → 경로가 뒤에 덧붙지 않음
// - 그 외 : 호스트 없음 + [어댑터경로 + 경로]
function resolveSpecServer() {
var d = state.data;
var rt = (d.portal && d.portal.responseType) || 'sample';
var path = d.operation.path.value;
if (rt === 'gw') {
return { host: (window.DJB_CTX && window.DJB_CTX.gwAddress) || 'http://127.0.0.1:39310', path: path };
}
if (rt === 'mock') {
var mk = splitFullUrl((d.portal && d.portal.mockUrl) || '');
return { host: mk.origin, path: mk.path };
}
return { host: '', path: path };
}
// 전체 URL → { origin, path }. Mock Server URL 을 서버+경로로 분해(경로를 별도로 덧붙이지 않기 위함).
function splitFullUrl(u) {
u = (u || '').trim();
@@ -1103,7 +1129,8 @@
}
function mountSwagger() {
const spec = buildOpenApiSpec();
// 미리보기는 실주소로 — sentinel 이 가짜 주소로 보이면 안 된다.
const spec = buildOpenApiSpec(true);
swaggerInstance = SwaggerUIBundle({
spec: spec,
domNode: $('#preview-swagger'),
@@ -1121,7 +1148,7 @@
function updateMonacoFromState() {
if (!monacoReady) return;
const spec = buildOpenApiSpec();
const spec = buildOpenApiSpec(true); // YAML 미리보기도 실주소 표시
const yaml = jsyaml.dump(spec, { noRefs: true, lineWidth: 120 });
if (monacoEditor.getValue() !== yaml) monacoEditor.setValue(yaml);
}
@@ -1620,7 +1647,7 @@
// 16. Export
// ============================================================
function downloadSpec(format) {
const spec = buildOpenApiSpec();
const spec = buildOpenApiSpec(true); // 편집기 다운로드는 실주소 산출물
if (format === 'yaml') { doDownload(jsyaml.dump(spec, { noRefs: true }), 'text/yaml', 'yaml'); return; }
if (format === 'json') { doDownload(JSON.stringify(spec, null, 2), 'application/json', 'json'); return; }
// html — 폐쇄망 자립: 벤더 swagger css/js 를 fetch 해 인라인
@@ -2023,6 +2050,7 @@
function saveSpec(temp) {
var ctx = window.DJB_CTX || {};
if (!ctx.saveUrl || !ctx.eaiSvcName) { toast('저장 대상이 없습니다', 'error'); return; }
// 저장본은 sentinel 유지 — 실주소는 포탈이 제공 시점에 응답유형별로 치환한다.
var spec = buildOpenApiSpec();
var d = state.data;
var reqEx = (d.examples && d.examples.request && d.examples.request[d.requestBody && d.requestBody.mediaType || 'application/json'] || {}).default || '';