스크립트 추가
This commit is contained in:
@@ -22,6 +22,10 @@ public class ApiRequestDTO {
|
|||||||
|
|
||||||
private String requestBody;
|
private String requestBody;
|
||||||
|
|
||||||
|
private String preRequestScript;
|
||||||
|
|
||||||
|
private String postRequestScript;
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@@ -93,4 +97,20 @@ public class ApiRequestDTO {
|
|||||||
public void setRequestBody(String requestBody) {
|
public void setRequestBody(String requestBody) {
|
||||||
this.requestBody = requestBody;
|
this.requestBody = requestBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPreRequestScript() {
|
||||||
|
return preRequestScript;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPreRequestScript(String preRequestScript) {
|
||||||
|
this.preRequestScript = preRequestScript;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPostRequestScript() {
|
||||||
|
return postRequestScript;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPostRequestScript(String postRequestScript) {
|
||||||
|
this.postRequestScript = postRequestScript;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,13 @@ public class ApiRequestInfo {
|
|||||||
@Lob
|
@Lob
|
||||||
private String requestBody;
|
private String requestBody;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
private String preRequestScript;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
private String postRequestScript;
|
||||||
|
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@@ -120,6 +127,22 @@ public class ApiRequestInfo {
|
|||||||
this.requestBody = requestBody;
|
this.requestBody = requestBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPreRequestScript() {
|
||||||
|
return preRequestScript;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPreRequestScript(String preRequestScript) {
|
||||||
|
this.preRequestScript = preRequestScript;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPostRequestScript() {
|
||||||
|
return postRequestScript;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPostRequestScript(String postRequestScript) {
|
||||||
|
this.postRequestScript = postRequestScript;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
@@ -130,7 +153,7 @@ public class ApiRequestInfo {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(id, server, owner, method, path, headers, queryParams, requestBody);
|
return Objects.hash(id, server, owner, method, path, headers, queryParams, requestBody, preRequestScript, postRequestScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,9 @@ public class ApiRequestMgmtService {
|
|||||||
existing.setVariables(api.getVariables());
|
existing.setVariables(api.getVariables());
|
||||||
existing.setServer(api.getServer());
|
existing.setServer(api.getServer());
|
||||||
existing.setRequestBody(api.getRequestBody());
|
existing.setRequestBody(api.getRequestBody());
|
||||||
|
existing.setPreRequestScript(api.getPreRequestScript());
|
||||||
|
existing.setPostRequestScript(api.getPostRequestScript());
|
||||||
|
|
||||||
apiRequestRepository.save(existing);
|
apiRequestRepository.save(existing);
|
||||||
api = existing;
|
api = existing;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class NettyApiClient {
|
|||||||
ServerRepository serverRepository;
|
ServerRepository serverRepository;
|
||||||
|
|
||||||
public CompletableFuture<ApiResponse> handleRequest(ApiRequestDTO originalRequest) throws InterruptedException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException {
|
public CompletableFuture<ApiResponse> handleRequest(ApiRequestDTO originalRequest) throws InterruptedException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException {
|
||||||
ApiRequestDTO apiRequest = replacePlaceholdersWithVariables(originalRequest);
|
ApiRequestDTO apiRequest = originalRequest;
|
||||||
Server server = serverRepository.findById(apiRequest.getServer()).orElseThrow(() -> new ServerNotFoundException("Server not found"));
|
Server server = serverRepository.findById(apiRequest.getServer()).orElseThrow(() -> new ServerNotFoundException("Server not found"));
|
||||||
String host = server.getHostname();
|
String host = server.getHostname();
|
||||||
int port = server.getPort();
|
int port = server.getPort();
|
||||||
@@ -108,37 +108,4 @@ public class NettyApiClient {
|
|||||||
return responseFuture;
|
return responseFuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ApiRequestDTO replacePlaceholdersWithVariables(ApiRequestDTO original) throws InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException {
|
|
||||||
ApiRequestDTO request = (ApiRequestDTO) BeanUtils.cloneBean(original);
|
|
||||||
if (request.getVariables() != null) {
|
|
||||||
for (ApiRequestKeyValueDTO variable : request.getVariables()) {
|
|
||||||
if (variable.isEnabled()) {
|
|
||||||
String placeholder = "{{" + variable.getKey() + "}}";
|
|
||||||
// Replace in path
|
|
||||||
request.setPath(request.getPath().replace(placeholder, variable.getValue()));
|
|
||||||
// Replace in requestBody
|
|
||||||
if (request.getRequestBody() != null) {
|
|
||||||
request.setRequestBody(request.getRequestBody().replace(placeholder, variable.getValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace in headers
|
|
||||||
if (request.getHeaders() != null) {
|
|
||||||
for (ApiRequestKeyValueDTO header : request.getHeaders()) {
|
|
||||||
header.setKey(header.getKey().replace(placeholder, variable.getValue()));
|
|
||||||
header.setValue(header.getValue().replace(placeholder, variable.getValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Replace in queryParams
|
|
||||||
if (request.getQueryParams() != null) {
|
|
||||||
for (ApiRequestKeyValueDTO queryParam : request.getQueryParams()) {
|
|
||||||
queryParam.setKey(queryParam.getKey().replace(placeholder, variable.getValue()));
|
|
||||||
queryParam.setValue(queryParam.getValue().replace(placeholder, variable.getValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,11 @@ class APITester {
|
|||||||
this.collections = []; //API 컬렉션
|
this.collections = []; //API 컬렉션
|
||||||
this.requestEditors = []; //API request body editor
|
this.requestEditors = []; //API request body editor
|
||||||
this.responseEditors = []; //API response body editor
|
this.responseEditors = []; //API response body editor
|
||||||
|
this.preRequestEditors = [];
|
||||||
|
this.postRequestEditors = [];
|
||||||
|
window.globals = {};
|
||||||
|
this.globalVariables = window.globals;
|
||||||
|
this.variables = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
renderServers(selectedServer) {
|
renderServers(selectedServer) {
|
||||||
@@ -36,7 +40,7 @@ class APITester {
|
|||||||
|
|
||||||
apiRequestTemplate(apiRequest, index) {
|
apiRequestTemplate(apiRequest, index) {
|
||||||
return `
|
return `
|
||||||
<div class="tab-pane fade mt-1 api_request" id="api_request_${apiRequest.id}" data-index="${index}">
|
<div class="tab-pane fade mt-1 api_request" id="api_request_${apiRequest.id}">
|
||||||
<div><span class="collection_name">${apiRequest.collectionName}</span> > <span class="api_name">${apiRequest.name}</span></div>
|
<div><span class="collection_name">${apiRequest.collectionName}</span> > <span class="api_name">${apiRequest.name}</span></div>
|
||||||
<div class="d-flex align-items-center api_request_info">
|
<div class="d-flex align-items-center api_request_info">
|
||||||
<div class="form-floating col-md-1 me-1">
|
<div class="form-floating col-md-1 me-1">
|
||||||
@@ -60,13 +64,12 @@ class APITester {
|
|||||||
<div class="form-floating col-md-2 me-1">
|
<div class="form-floating col-md-2 me-1">
|
||||||
<div class="form-floating col-md">
|
<div class="form-floating col-md">
|
||||||
<input type="text" name="basePath" class="form-control" value="${this.basePath(apiRequest.server)}" readonly>
|
<input type="text" name="basePath" class="form-control" value="${this.basePath(apiRequest.server)}" readonly>
|
||||||
<label class="must">base path</label>
|
<label class="must">기본 경로</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group col-md me-1">
|
<div class="input-group col-md me-1">
|
||||||
<div class="form-floating col-md">
|
<div class="form-floating col-md">
|
||||||
<input type="text" name="path" class="form-control path" value="${apiRequest.path}" placeholder="호출할 경로 (/부터 입력)"
|
<input type="text" name="path" class="form-control path" value="${apiRequest.path}" placeholder="호출할 경로 (/부터 입력)">
|
||||||
required>
|
|
||||||
<label class="must">Path</label>
|
<label class="must">Path</label>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary send">Send</button>
|
<button class="btn btn-primary send">Send</button>
|
||||||
@@ -98,6 +101,19 @@ class APITester {
|
|||||||
aria-selected="false">Variables
|
aria-selected="false">Variables
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link btn_prerequest_tab" data-bs-toggle="tab"
|
||||||
|
type="button" role="tab" aria-controls="preScrit" data-bs-target="#preRequestTab_${apiRequest.id}"
|
||||||
|
aria-selected="false">Pre-Request
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link btn_postrequest_tab" data-bs-toggle="tab"
|
||||||
|
type="button" role="tab" aria-controls="postScript" data-bs-target="#postRequestTab_${apiRequest.id}"
|
||||||
|
aria-selected="false">Post-Request
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content border-bottom" style="min-height: 300px;">
|
<div class="tab-content border-bottom" style="min-height: 300px;">
|
||||||
<div class="tab-pane fade show request_param_tab" role="tabpanel" id="requestParamTab_${apiRequest.id}"
|
<div class="tab-pane fade show request_param_tab" role="tabpanel" id="requestParamTab_${apiRequest.id}"
|
||||||
@@ -164,6 +180,14 @@ class APITester {
|
|||||||
</select>
|
</select>
|
||||||
<div class="request_body mt-1" style="width:100%;height:250px;border:1px solid grey;"></div>
|
<div class="request_body mt-1" style="width:100%;height:250px;border:1px solid grey;"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tab-pane fade pre_script_tab" role="tabpanel" id="preRequestTab_${apiRequest.id}"
|
||||||
|
aria-labelledby="preScrit-tab">
|
||||||
|
<div class="pre-request mt-1" style="width:100%;height:250px;border:1px solid grey;"></div>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane fade post_script_tab" role="tabpanel" id="postRequestTab_${apiRequest.id}"
|
||||||
|
aria-labelledby="postScrit-tab">
|
||||||
|
<div class="post-request mt-1" style="width:100%;height:250px;border:1px solid grey;"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
<span>Response</span>
|
<span>Response</span>
|
||||||
@@ -467,8 +491,7 @@ class APITester {
|
|||||||
//console.log(fieldName);
|
//console.log(fieldName);
|
||||||
const newValue = this.getFieldValue(element);
|
const newValue = this.getFieldValue(element);
|
||||||
//console.log(newValue);
|
//console.log(newValue);
|
||||||
|
const tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));
|
||||||
const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
|
|
||||||
let model = this.apiRequests[tabIndex];
|
let model = this.apiRequests[tabIndex];
|
||||||
|
|
||||||
if (fieldName !== '') {
|
if (fieldName !== '') {
|
||||||
@@ -479,7 +502,7 @@ class APITester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleUpdateServer(event) {
|
handleUpdateServer(event) {
|
||||||
const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
|
const tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));
|
||||||
let model = this.apiRequests[tabIndex];
|
let model = this.apiRequests[tabIndex];
|
||||||
let target = $('#api_request_' + model.id);
|
let target = $('#api_request_' + model.id);
|
||||||
//console.log('model.server: ' + model.server);
|
//console.log('model.server: ' + model.server);
|
||||||
@@ -505,7 +528,7 @@ class APITester {
|
|||||||
|
|
||||||
for (let idx = 0; idx < this.apiRequests.length; idx++) {
|
for (let idx = 0; idx < this.apiRequests.length; idx++) {
|
||||||
let li = `<li class="nav-item" role="presentation">
|
let li = `<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link" id="api_request_tab_${this.apiRequests[idx].id}" data-index="${idx}" data-bs-toggle="tab" type="button" role="tab" aria-controls="api_request_${this.apiRequests[idx].id}" data-bs-target="#api_request_${this.apiRequests[idx].id}" aria-selected="false">${this.apiRequests[idx].name}
|
<button class="nav-link" id="api_request_tab_${this.apiRequests[idx].id}" data-bs-toggle="tab" type="button" role="tab" aria-controls="api_request_${this.apiRequests[idx].id}" data-bs-target="#api_request_${this.apiRequests[idx].id}" aria-selected="false">${this.apiRequests[idx].name}
|
||||||
<span class="close_tab"><i class="fa fa-light fa-close"></i></span>
|
<span class="close_tab"><i class="fa fa-light fa-close"></i></span>
|
||||||
</button>
|
</button>
|
||||||
</li>`;
|
</li>`;
|
||||||
@@ -524,7 +547,7 @@ class APITester {
|
|||||||
this.openTab(model.id);
|
this.openTab(model.id);
|
||||||
let target = $('#api_request_' + model.id);
|
let target = $('#api_request_' + model.id);
|
||||||
|
|
||||||
require(['vs/editor/editor.main'], function () {
|
require(['vs/editor/editor.main'], () => {
|
||||||
let requestBodyEditor = monaco.editor.create(target.find(".request_body")[0], {
|
let requestBodyEditor = monaco.editor.create(target.find(".request_body")[0], {
|
||||||
value: model.requestBody,
|
value: model.requestBody,
|
||||||
language: 'json',
|
language: 'json',
|
||||||
@@ -532,15 +555,15 @@ class APITester {
|
|||||||
automaticLayout: true
|
automaticLayout: true
|
||||||
});
|
});
|
||||||
me.requestEditors.push(requestBodyEditor);
|
me.requestEditors.push(requestBodyEditor);
|
||||||
target.find(".request_body")[0].addEventListener('shown.bs.tab', function () {
|
target.find(".request_body")[0].addEventListener('shown.bs.tab', () => {
|
||||||
me.requestEditors[index].layout();
|
me.requestEditors[index].layout();
|
||||||
});
|
});
|
||||||
|
|
||||||
me.requestEditors[index].onDidChangeModelContent(function (e) {
|
me.requestEditors[index].onDidChangeModelContent( (e) => {
|
||||||
model.requestBody = requestBodyEditor.getValue();
|
model.requestBody = requestBodyEditor.getValue();
|
||||||
});
|
});
|
||||||
|
|
||||||
target.find('.request_body_type').on('change', function () {
|
target.find('.request_body_type').on('change', () => {
|
||||||
let model = requestBodyEditor.getModel();
|
let model = requestBodyEditor.getModel();
|
||||||
monaco.editor.setModelLanguage(model, $(this).val());
|
monaco.editor.setModelLanguage(model, $(this).val());
|
||||||
});
|
});
|
||||||
@@ -552,6 +575,40 @@ class APITester {
|
|||||||
automaticLayout: true
|
automaticLayout: true
|
||||||
});
|
});
|
||||||
me.responseEditors.push(responseBodyEditor);
|
me.responseEditors.push(responseBodyEditor);
|
||||||
|
|
||||||
|
let preRequestEditor = monaco.editor.create(target.find(".pre-request")[0], {
|
||||||
|
value: model.preRequestScript,
|
||||||
|
language: 'javascript',
|
||||||
|
theme: 'vs-light',
|
||||||
|
automaticLayout: true
|
||||||
|
});
|
||||||
|
me.preRequestEditors.push(preRequestEditor);
|
||||||
|
target.find(".pre-request")[0].addEventListener('shown.bs.tab', () => {
|
||||||
|
me.preRequestEditors[index].layout();
|
||||||
|
});
|
||||||
|
|
||||||
|
me.preRequestEditors[index].onDidChangeModelContent( (e) => {
|
||||||
|
model.preRequestScript = preRequestEditor.getValue();
|
||||||
|
});
|
||||||
|
|
||||||
|
let postRequestEditor = monaco.editor.create(target.find(".post-request")[0], {
|
||||||
|
value: model.postRequestScript,
|
||||||
|
language: 'javascript',
|
||||||
|
theme: 'vs-light',
|
||||||
|
automaticLayout: true
|
||||||
|
});
|
||||||
|
me.postRequestEditors.push(postRequestEditor);
|
||||||
|
target.find(".post-request")[0].addEventListener('shown.bs.tab', () => {
|
||||||
|
me.postRequestEditors[index].layout();
|
||||||
|
});
|
||||||
|
|
||||||
|
me.postRequestEditors[index].onDidChangeModelContent( (e) => {
|
||||||
|
model.postRequestScript = postRequestEditor.getValue();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,7 +678,7 @@ class APITester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addHeader(event) {
|
addHeader(event) {
|
||||||
const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
|
const tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));
|
||||||
let model = this.apiRequests[tabIndex];
|
let model = this.apiRequests[tabIndex];
|
||||||
model.headers.push({
|
model.headers.push({
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -632,7 +689,7 @@ class APITester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
removeHeader(event) {
|
removeHeader(event) {
|
||||||
const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
|
const tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));
|
||||||
const index = $(event.currentTarget).closest('tr').data('index');
|
const index = $(event.currentTarget).closest('tr').data('index');
|
||||||
let model = this.apiRequests[tabIndex];
|
let model = this.apiRequests[tabIndex];
|
||||||
model.headers.splice(index, 1);
|
model.headers.splice(index, 1);
|
||||||
@@ -649,7 +706,7 @@ class APITester {
|
|||||||
|
|
||||||
|
|
||||||
addQueryParam(event) {
|
addQueryParam(event) {
|
||||||
const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
|
const tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));
|
||||||
//console.log('addQueryParam');
|
//console.log('addQueryParam');
|
||||||
let model = this.apiRequests[tabIndex];
|
let model = this.apiRequests[tabIndex];
|
||||||
model.queryParams.push({
|
model.queryParams.push({
|
||||||
@@ -663,7 +720,7 @@ class APITester {
|
|||||||
|
|
||||||
removeQueryParam(event) {
|
removeQueryParam(event) {
|
||||||
//console.log('removeQueryParam');
|
//console.log('removeQueryParam');
|
||||||
const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
|
const tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));
|
||||||
const index = $(event.currentTarget).closest('tr').data('index');
|
const index = $(event.currentTarget).closest('tr').data('index');
|
||||||
let model = this.apiRequests[tabIndex];
|
let model = this.apiRequests[tabIndex];
|
||||||
model.queryParams.splice(index, 1);
|
model.queryParams.splice(index, 1);
|
||||||
@@ -680,7 +737,7 @@ class APITester {
|
|||||||
|
|
||||||
addVariable(event) {
|
addVariable(event) {
|
||||||
//console.log('addVariable');
|
//console.log('addVariable');
|
||||||
const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
|
const tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));
|
||||||
let model = this.apiRequests[tabIndex];
|
let model = this.apiRequests[tabIndex];
|
||||||
model.variables.push({
|
model.variables.push({
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -692,7 +749,7 @@ class APITester {
|
|||||||
|
|
||||||
removeVariable(event) {
|
removeVariable(event) {
|
||||||
//console.log('removeVariable');
|
//console.log('removeVariable');
|
||||||
const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
|
const tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));
|
||||||
const index = $(event.currentTarget).closest('tr').data('index');
|
const index = $(event.currentTarget).closest('tr').data('index');
|
||||||
let model = this.apiRequests[tabIndex];
|
let model = this.apiRequests[tabIndex];
|
||||||
model.variables.splice(index, 1);
|
model.variables.splice(index, 1);
|
||||||
@@ -707,7 +764,7 @@ class APITester {
|
|||||||
target.find('.variables').append(this.renderVariables(model.variables));
|
target.find('.variables').append(this.renderVariables(model.variables));
|
||||||
}
|
}
|
||||||
parseParam(event) {
|
parseParam(event) {
|
||||||
const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
|
const tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));
|
||||||
let model = this.apiRequests[tabIndex];
|
let model = this.apiRequests[tabIndex];
|
||||||
model.path = $(event.currentTarget).val();
|
model.path = $(event.currentTarget).val();
|
||||||
//console.log(model.path);
|
//console.log(model.path);
|
||||||
@@ -729,7 +786,7 @@ class APITester {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
buildPath(event) {
|
buildPath(event) {
|
||||||
const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
|
const tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));
|
||||||
let model = this.apiRequests[tabIndex];
|
let model = this.apiRequests[tabIndex];
|
||||||
let queryString = model.path.split('?')[0];
|
let queryString = model.path.split('?')[0];
|
||||||
if (model.queryParams.length > 0) {
|
if (model.queryParams.length > 0) {
|
||||||
@@ -757,41 +814,65 @@ class APITester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sendApiRequest(event) {
|
sendApiRequest(event) {
|
||||||
const tabIndex = $(event.currentTarget).closest('.api_request').data('index');
|
const tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));
|
||||||
|
console.log(tabIndex);
|
||||||
const me = this;
|
const me = this;
|
||||||
|
|
||||||
let model = this.apiRequests[tabIndex];
|
let model = this.apiRequests[tabIndex];
|
||||||
|
|
||||||
|
if (!model.server){
|
||||||
|
$('.toast-body').text('서버를 등록해주세요.');
|
||||||
|
$('.toast').toast('show');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let target = $('#api_request_' + model.id);
|
let target = $('#api_request_' + model.id);
|
||||||
target.find('.response_headers').empty();
|
target.find('.response_headers').empty();
|
||||||
this.responseEditors[tabIndex].setValue('');
|
this.responseEditors[tabIndex].setValue('');
|
||||||
let startTime = new Date().getTime();
|
let startTime = new Date().getTime();
|
||||||
|
|
||||||
if (model.path !== '') {
|
this.showLoadingOverlay();
|
||||||
this.showLoadingOverlay();
|
model.responseModel = {};
|
||||||
|
|
||||||
|
let processedRequest = this.executePreRequestScript(model, tabIndex,() => {
|
||||||
|
processedRequest = this.replacePlaceholdersWithVariables(processedRequest, tabIndex);
|
||||||
this.currentAjaxRequest = $.ajax({
|
this.currentAjaxRequest = $.ajax({
|
||||||
url: '/mgmt/api/test.do',
|
url: '/mgmt/api/test.do',
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
contentType: 'application/json',
|
contentType: 'application/json',
|
||||||
data: JSON.stringify(model),
|
data: JSON.stringify(processedRequest),
|
||||||
success: function (data) {
|
success: (data) => {
|
||||||
model.responseModel.status = data.status;
|
model.responseModel.status = data.status;
|
||||||
model.responseModel.body = data.body;
|
model.responseModel.body = data.body;
|
||||||
model.responseModel.headers = data.headers;
|
model.responseModel.headers = data.headers;
|
||||||
model.responseModel.size = data.size;
|
model.responseModel.size = data.size;
|
||||||
|
|
||||||
|
let response = {};
|
||||||
|
response.body = data.body;
|
||||||
|
response.status = data.status;
|
||||||
|
response.headers = {};
|
||||||
|
response.size = data.size;
|
||||||
|
_.forEach(data.headers, (header) => {
|
||||||
|
response.headers[header.key] = header.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
this.executePostRequestScript(model.postRequestScript, tabIndex, response, ()=> {
|
||||||
|
let endTime = new Date().getTime();
|
||||||
|
model.responseModel.time = endTime - startTime;
|
||||||
|
me.renderResponse(tabIndex);
|
||||||
|
me.hideLoadingOverlay();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
error: function (response, textStatus, errorThrown) {
|
error: (response, textStatus, errorThrown) => {
|
||||||
me.hideLoadingOverlay();
|
me.hideLoadingOverlay();
|
||||||
$('.toast-body').text(response.responseJSON.error);
|
$('.toast-body').text(response.responseJSON.error);
|
||||||
$('.toast').toast('show');
|
$('.toast').toast('show');
|
||||||
},
|
|
||||||
complete: function () {
|
|
||||||
let endTime = new Date().getTime();
|
|
||||||
model.responseModel.time = endTime - startTime;
|
|
||||||
me.renderResponse(tabIndex);
|
|
||||||
me.hideLoadingOverlay();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -917,7 +998,7 @@ class APITester {
|
|||||||
|
|
||||||
saveAPIRequest(event) {
|
saveAPIRequest(event) {
|
||||||
const me = this;
|
const me = this;
|
||||||
const index = $(event.currentTarget).data('index');
|
const index = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));
|
||||||
let model = this.apiRequests[index];
|
let model = this.apiRequests[index];
|
||||||
me.showLoadingOverlay();
|
me.showLoadingOverlay();
|
||||||
|
|
||||||
@@ -946,6 +1027,11 @@ class APITester {
|
|||||||
|
|
||||||
addAPIRequest(event) {
|
addAPIRequest(event) {
|
||||||
const collectionId = $('#modal_collection').val();
|
const collectionId = $('#modal_collection').val();
|
||||||
|
let newApiName = $('#new_api_name').val();
|
||||||
|
if (newApiName === '') {
|
||||||
|
newApiName = '새로운 API';
|
||||||
|
}
|
||||||
|
|
||||||
const collection = this.collections.filter(function (collection) {
|
const collection = this.collections.filter(function (collection) {
|
||||||
return collection.id === collectionId;
|
return collection.id === collectionId;
|
||||||
})[0];
|
})[0];
|
||||||
@@ -954,12 +1040,14 @@ class APITester {
|
|||||||
id: '',
|
id: '',
|
||||||
server: null,
|
server: null,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
name: 'New Request',
|
name: newApiName,
|
||||||
path: '',
|
path: '',
|
||||||
headers: [],
|
headers: [],
|
||||||
queryParams: [],
|
queryParams: [],
|
||||||
variables: [],
|
variables: [],
|
||||||
requestBody: '',
|
requestBody: '',
|
||||||
|
preRequestScript :'',
|
||||||
|
postRequestScript :'',
|
||||||
collectionId: collectionId,
|
collectionId: collectionId,
|
||||||
responseModel: {
|
responseModel: {
|
||||||
status: 0,
|
status: 0,
|
||||||
@@ -991,7 +1079,7 @@ class APITester {
|
|||||||
|
|
||||||
me.renderTabHeader();
|
me.renderTabHeader();
|
||||||
me.renderTabContent(me.currentIndex);
|
me.renderTabContent(me.currentIndex);
|
||||||
|
$('#new_api_name').val('');
|
||||||
me.hideLoadingOverlay();
|
me.hideLoadingOverlay();
|
||||||
$('#new_api_request_modal').modal('hide');
|
$('#new_api_request_modal').modal('hide');
|
||||||
}
|
}
|
||||||
@@ -1078,28 +1166,123 @@ class APITester {
|
|||||||
me.hideLoadingOverlay();
|
me.hideLoadingOverlay();
|
||||||
me.loadCollections();
|
me.loadCollections();
|
||||||
$('#confirm_delete_api_modal').modal('hide');
|
$('#confirm_delete_api_modal').modal('hide');
|
||||||
// $('#confirm_delete_api_modal').find('.confirm_delete_api').removeAttr('data-id');
|
|
||||||
// $('#confirm_delete_api_modal').find('.confirm_delete_api').removeAttr('data-collection');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
closeTabWithApiIndex(index) {
|
closeTabWithApiIndex(index) {
|
||||||
|
console.log(index);
|
||||||
if (index !== undefined){
|
if (index !== undefined){
|
||||||
//console.log('closeTabWithApiIndex: ' + index);
|
//console.log('closeTabWithApiIndex: ' + index);
|
||||||
const model = this.apiRequests[index];
|
const model = this.apiRequests[index];
|
||||||
|
console.log(model);
|
||||||
this.apiRequests.splice(index, 1);
|
this.apiRequests.splice(index, 1);
|
||||||
|
|
||||||
let apiRequestTabTitle = $(this.apiTabTitleTarget);
|
let apiRequestTabTitle = $(this.apiTabTitleTarget);
|
||||||
apiRequestTabTitle.empty();
|
apiRequestTabTitle.empty();
|
||||||
this.renderTabHeader();
|
this.renderTabHeader();
|
||||||
$(`#api_request_${model.id}`).remove();
|
$(`#api_request_${model.id}`).remove();
|
||||||
$(`#apiRequestTabTitle li:eq(${this.apiRequests.length - 1}) button`).tab('show');
|
// $(`#apiRequestTabTitle li:eq(${this.apiRequests.length - 1}) button`).tab('show');
|
||||||
|
$(`#apiRequestTabTitle li:eq(0) button`).tab('show');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closeTab(event) {
|
closeTab(event) {
|
||||||
let index = $(event.currentTarget).closest('button').data('index');
|
const index = $('#apiRequestTabTitle').children().index($(event.currentTarget).closest('.nav-item'));
|
||||||
//console.log('closeTab: ' + index);
|
|
||||||
this.closeTabWithApiIndex(index);
|
this.closeTabWithApiIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
replacePlaceholdersWithVariables(original, index) {
|
||||||
|
let request = JSON.parse(JSON.stringify(original));
|
||||||
|
|
||||||
|
let mergedVariables = {};
|
||||||
|
_.forEach(this.globalVariables, (value, key) => {
|
||||||
|
mergedVariables[key] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.variables[index]) {
|
||||||
|
_.forEach(this.variables[index], (value, key) => {
|
||||||
|
mergedVariables[key] = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_.forEach(mergedVariables, (value, key) => {
|
||||||
|
const placeholder = `{{${key}}}`;
|
||||||
|
// Replace in path
|
||||||
|
request.path = request.path.replace(new RegExp(placeholder, 'g'), value);
|
||||||
|
|
||||||
|
// Replace in requestBody
|
||||||
|
if (request.requestBody) {
|
||||||
|
request.requestBody = request.requestBody.replace(new RegExp(placeholder, 'g'), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace in headers
|
||||||
|
if (request.headers) {
|
||||||
|
request.headers = request.headers.map(header => {
|
||||||
|
return {
|
||||||
|
...header,
|
||||||
|
key: header.key.replace(new RegExp(placeholder, 'g'), value),
|
||||||
|
value: header.value.replace(new RegExp(placeholder, 'g'), value)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace in queryParams
|
||||||
|
if (request.queryParams) {
|
||||||
|
request.queryParams = request.queryParams.map(queryParam => {
|
||||||
|
return {
|
||||||
|
...queryParam,
|
||||||
|
key: queryParam.key.replace(new RegExp(placeholder, 'g'), value),
|
||||||
|
value: queryParam.value.replace(new RegExp(placeholder, 'g'), value)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
executePreRequestScript(model, index, callback) {
|
||||||
|
let script = model.preRequestScript;
|
||||||
|
let resultFrame = document.getElementById('preRequest');
|
||||||
|
let {headers, method, path, queryParams, requestBody} = model;
|
||||||
|
window.request = {headers, method, path, queryParams, requestBody};
|
||||||
|
this.variables[index] = {};
|
||||||
|
model.variables.forEach((item) =>{
|
||||||
|
if (item.enabled) {
|
||||||
|
this.variables[index][item.key] = item.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.preRequestComplete = function(updatedModel) {
|
||||||
|
callback(updatedModel);
|
||||||
|
};
|
||||||
|
window.temp_variable = this.variables[index];
|
||||||
|
|
||||||
|
resultFrame.srcdoc = `<script>
|
||||||
|
window.globals = window.parent.globals;
|
||||||
|
window.variables = window.parent.temp_variable;
|
||||||
|
window.request = window.parent.request;
|
||||||
|
${script}
|
||||||
|
window.parent.preRequestComplete(window.request);
|
||||||
|
</script>`;
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
executePostRequestScript(script, index, response, callback) {
|
||||||
|
let resultFrame = document.getElementById('postRequest');
|
||||||
|
window.response = response;
|
||||||
|
window.parent.temp_variable = this.variables[index];
|
||||||
|
window.postRequestComplete = function(updatedModel) {
|
||||||
|
callback(updatedModel);
|
||||||
|
};
|
||||||
|
window.temp_variable = this.variables[index];
|
||||||
|
resultFrame.srcdoc = `<script>
|
||||||
|
window.globals = window.parent.globals;
|
||||||
|
window.variables = window.parent.temp_variable;
|
||||||
|
window.response = window.parent.response;
|
||||||
|
${script}
|
||||||
|
window.parent.postRequestComplete(window.request);
|
||||||
|
</script>`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
class LayoutUtil {
|
||||||
|
static flattenObject(obj, prefix = '') {
|
||||||
|
return _.reduce(obj, (acc, value, key) => {
|
||||||
|
const fullKey = prefix ? `${prefix}.${key}` : key;
|
||||||
|
if (_.isObject(value) && !_.isArray(value)) {
|
||||||
|
_.assign(acc, this.flattenObject(value, fullKey));
|
||||||
|
} else if (_.isArray(value)) {
|
||||||
|
// Process each item in the array
|
||||||
|
value.forEach((item, index) => {
|
||||||
|
// If the item is an object, recurse, otherwise assign directly
|
||||||
|
if (_.isObject(item)) {
|
||||||
|
_.assign(acc, this.flattenObject(item, `${fullKey}[${index}]`));
|
||||||
|
} else {
|
||||||
|
acc[`${fullKey}[${index}]`] = item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
acc[fullKey] = value;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
static createGroup(groupModel) {
|
||||||
|
let groupHtml = `<div><h6>${groupModel.groupTitle}</h6>`;
|
||||||
|
|
||||||
|
groupModel.fields.forEach(item => {
|
||||||
|
groupHtml += this.createFormElement(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
groupHtml += '</div>';
|
||||||
|
return groupHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
static createTextInput(elementModel) {
|
||||||
|
return `
|
||||||
|
<div class="form-floating mb-2">
|
||||||
|
<input type="text" name="${elementModel.path}" class="form-control mb-2" id="${elementModel.path}" placeholder="${elementModel.placeholder}">
|
||||||
|
<label for="${elementModel.path}" class="form-label">${elementModel.label}</label>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static createBooleanInput(elementModel) {
|
||||||
|
return `
|
||||||
|
<div class="form-floating mb-2">
|
||||||
|
<div class="form-check form-check-inline">
|
||||||
|
<input type="checkbox" name="${elementModel.path}" class="form-check-input mb-2" id="${elementModel.path}" placeholder="${elementModel.placeholder}">
|
||||||
|
<label class="form-check-label" for="${elementModel.path}" class="form-label">${elementModel.label}</label>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static createSelectInput(elementModel) {
|
||||||
|
const optionsHtml = elementModel.options.map(optionValue => `<option value="${optionValue}">${optionValue}</option>`).join('');
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="form-floating mb-2">
|
||||||
|
<select class="form-select mb-2" id="${elementModel.path}" name="${elementModel.path}">
|
||||||
|
${optionsHtml}
|
||||||
|
</select>
|
||||||
|
<label for="${elementModel.path}" class="form-label">${elementModel.label}</label>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static createTextAreaInput(elementModel) {
|
||||||
|
return `
|
||||||
|
<div class="form-floating mb-2">
|
||||||
|
<textarea class="form-control mb-2" name="${elementModel.path}" id="${elementModel.path}" placeholder="${elementModel.placeholder}"></textarea>
|
||||||
|
<label for="${elementModel.path}" class="form-label">${elementModel.label}</label>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static createFormElement(elementModel) {
|
||||||
|
switch (elementModel.type) {
|
||||||
|
case "boolean":
|
||||||
|
return this.createBooleanInput(elementModel);
|
||||||
|
case "text":
|
||||||
|
return this.createTextInput(elementModel);
|
||||||
|
case "select":
|
||||||
|
return this.createSelectInput(elementModel);
|
||||||
|
case "textarea":
|
||||||
|
return this.createTextAreaInput(elementModel);
|
||||||
|
default:
|
||||||
|
console.error("Unsupported element type: " + elementModel.type);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static createForm(model) {
|
||||||
|
let formHtml = '';
|
||||||
|
model.forEach(group => {
|
||||||
|
formHtml += this.createGroup(group);
|
||||||
|
});
|
||||||
|
return formHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getFieldValue(element) {
|
||||||
|
if ($(element).is('select') || $(element).is('input[type="text"]') || $(element).is('textarea')) {
|
||||||
|
return $(element).val();
|
||||||
|
}
|
||||||
|
if ($(element).is('input[type="checkbox"]')) {
|
||||||
|
return $(element).is(':checked');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static echartReplacer(key, value) {
|
||||||
|
if (key === 'echart' || key === 'series') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,6 +48,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<select class="form-select" id="modal_collection"></select>
|
<select class="form-select" id="modal_collection"></select>
|
||||||
|
<div class="input-group mt-2">
|
||||||
|
<span class="input-group-text">API 이름</span>
|
||||||
|
<input type="text" class="form-control" id="new_api_name">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
|
||||||
@@ -61,11 +65,14 @@
|
|||||||
<li th:each="server : ${servers}" th:data-id="${server.id}" th:data-name="${server.name}" th:data-path="${server.basePath}"></li>
|
<li th:each="server : ${servers}" th:data-id="${server.id}" th:data-name="${server.name}" th:data-path="${server.basePath}"></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<iframe id="preRequest" class="preRequest"></iframe>
|
||||||
|
<iframe id="postRequest" class="postRequest"></iframe>
|
||||||
</section>
|
</section>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
<th:block layout:fragment="contentScript">
|
<th:block layout:fragment="contentScript">
|
||||||
<script th:src="@{/js/APITester.js}"></script>
|
<script th:src="@{/js/APITester.js}"></script>
|
||||||
|
<script th:src="@{/js/LayoutUtil.js}"></script>
|
||||||
<script>
|
<script>
|
||||||
$(document).ajaxError(function(event, jqxhr, settings, exception) {
|
$(document).ajaxError(function(event, jqxhr, settings, exception) {
|
||||||
if (jqxhr.status === 401) {
|
if (jqxhr.status === 401) {
|
||||||
|
|||||||
Reference in New Issue
Block a user