요청 관리 -> variable 적용
This commit is contained in:
@@ -39,12 +39,17 @@ public class MockApiController {
|
||||
public ResponseEntity<String> handleRequest(HttpServletRequest httpRequest) throws IOException {
|
||||
MockRequest request = new MockRequest(httpRequest);
|
||||
AntPathMatcher pathMatcher = new AntPathMatcher();
|
||||
logger.debug("===========================");
|
||||
logger.debug("Request: " + request.getMethod() + " " + request.getUri());
|
||||
logger.debug("Headers:" + request.getHeaders().toString());
|
||||
logger.debug("Params: " + request.getParams().toString());
|
||||
logger.debug("Body: ");
|
||||
logger.debug(request.getBody());
|
||||
logger.debug("===========================");
|
||||
|
||||
for (MockRoute mockRoute : mockRouteService.getAllRoutes()) {
|
||||
if (isRouteMatch(mockRoute, request)) {
|
||||
logger.debug("===========================");
|
||||
logger.debug(request.getBody());
|
||||
logger.debug("===========================");
|
||||
|
||||
Map<String, String> pathVariables = pathMatcher.extractUriTemplateVariables(mockRoute.getPathPattern(), request.getUri());
|
||||
MockResponse matchingResponse = findMatchingResponse(mockRoute, request, pathVariables);
|
||||
if (matchingResponse != null) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@@ -29,7 +30,7 @@ public class ApiClientController {
|
||||
|
||||
@PostMapping("/mgmt/api/test.do")
|
||||
@ResponseBody
|
||||
public ApiResponse handleApiRequest(@RequestBody ApiRequestDTO request) throws InterruptedException, ExecutionException {
|
||||
public ApiResponse handleApiRequest(@RequestBody ApiRequestDTO request) throws InterruptedException, ExecutionException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException {
|
||||
|
||||
return nettyApiClient.handleRequest(request).get();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ public class ApiRequestDTO {
|
||||
private List<ApiRequestKeyValueDTO> headers = new ArrayList<>();
|
||||
|
||||
private List<ApiRequestKeyValueDTO> queryParams = new ArrayList<>();
|
||||
|
||||
private List<ApiRequestKeyValueDTO> variables = new ArrayList<>();
|
||||
|
||||
private String requestBody;
|
||||
|
||||
public String getId() {
|
||||
@@ -75,6 +78,14 @@ public class ApiRequestDTO {
|
||||
this.queryParams = queryParams;
|
||||
}
|
||||
|
||||
public List<ApiRequestKeyValueDTO> getVariables() {
|
||||
return variables;
|
||||
}
|
||||
|
||||
public void setVariables(List<ApiRequestKeyValueDTO> variables) {
|
||||
this.variables = variables;
|
||||
}
|
||||
|
||||
public String getRequestBody() {
|
||||
return requestBody;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,9 @@ public class ApiRequestInfo {
|
||||
@Lob
|
||||
private String queryParams;
|
||||
|
||||
@Lob
|
||||
private String variables;
|
||||
|
||||
@Lob
|
||||
private String requestBody;
|
||||
|
||||
@@ -101,6 +104,14 @@ public class ApiRequestInfo {
|
||||
this.queryParams = queryParams;
|
||||
}
|
||||
|
||||
public String getVariables() {
|
||||
return variables;
|
||||
}
|
||||
|
||||
public void setVariables(String variables) {
|
||||
this.variables = variables;
|
||||
}
|
||||
|
||||
public String getRequestBody() {
|
||||
return requestBody;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ public class ApiRequestMgmtService {
|
||||
existing.setPath(api.getPath());
|
||||
existing.setHeaders(api.getHeaders());
|
||||
existing.setQueryParams(api.getQueryParams());
|
||||
existing.setVariables(api.getVariables());
|
||||
existing.setServer(api.getServer());
|
||||
existing.setRequestBody(api.getRequestBody());
|
||||
apiRequestRepository.save(existing);
|
||||
|
||||
@@ -20,11 +20,13 @@ import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.SslContextBuilder;
|
||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@@ -34,8 +36,8 @@ public class NettyApiClient {
|
||||
@Autowired
|
||||
ServerRepository serverRepository;
|
||||
|
||||
public CompletableFuture<ApiResponse> handleRequest(ApiRequestDTO apiRequest) throws InterruptedException {
|
||||
|
||||
public CompletableFuture<ApiResponse> handleRequest(ApiRequestDTO originalRequest) throws InterruptedException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException {
|
||||
ApiRequestDTO apiRequest = replacePlaceholdersWithVariables(originalRequest);
|
||||
Server server = serverRepository.findById(apiRequest.getServer()).orElseThrow(() -> new ServerNotFoundException("Server not found"));
|
||||
String host = server.getHostname();
|
||||
int port = server.getPort();
|
||||
@@ -103,5 +105,35 @@ public class NettyApiClient {
|
||||
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 requestBody
|
||||
request.setPath(request.getPath().replace(placeholder, variable.getValue()));
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -682,8 +682,6 @@ a.btn.btn-primary {
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.pt-links {
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: 5rem;
|
||||
display: block !important;
|
||||
height: calc(100vh - 7rem);
|
||||
@@ -809,8 +807,6 @@ a.btn.btn-primary {
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.pt-toc {
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: 5rem;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -115,6 +115,12 @@
|
||||
aria-selected="false">Header
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link btn_variables_tab" data-bs-toggle="tab"
|
||||
type="button" role="tab" aria-controls="variables"
|
||||
aria-selected="false">Variables
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content border-bottom" style="min-height: 300px;">
|
||||
<div class="tab-pane fade show request_param_tab" role="tabpanel"
|
||||
@@ -126,8 +132,7 @@
|
||||
<th scope="col">이름</th>
|
||||
<th>값</th>
|
||||
<th>
|
||||
<button type="button" class="btn btn-secondary btn-sm btn_add_query">추가
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary btn-sm btn_add_query">추가</button>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -144,8 +149,7 @@
|
||||
<th scope="col">이름</th>
|
||||
<th scope="col">값</th>
|
||||
<th scope="col">
|
||||
<button type="button" class="btn btn-secondary btn-sm btn_add_header">추가
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary btn-sm btn_add_header">추가</button>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -153,6 +157,24 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab-pane fade variables_tab" role="tabpanel"
|
||||
aria-labelledby="variables-tab">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">키</th>
|
||||
<th scope="col">값</th>
|
||||
<th scope="col">
|
||||
<button type="button" class="btn btn-secondary btn-sm btn_add_variables">추가
|
||||
</button>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="variables">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab-pane fade request_body_tab" role="tabpanel"
|
||||
aria-labelledby="requestBody-tab">
|
||||
<select class="form-select mt-1 request_body_type" name="request_type">
|
||||
@@ -171,17 +193,10 @@
|
||||
</div>
|
||||
<ul class="nav nav-tabs mt-1" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" data-bs-toggle="tab"
|
||||
data-bs-target="#responseBodyTab" type="button" role="tab" aria-controls="responseBody"
|
||||
aria-selected="false">Body
|
||||
</button>
|
||||
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#responseBodyTab" type="button" role="tab" aria-controls="responseBody" aria-selected="false">Body</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" data-bs-toggle="tab"
|
||||
data-bs-target="#responseHeaderTab" type="button" role="tab"
|
||||
aria-controls="responseHeader"
|
||||
aria-selected="false">Header
|
||||
</button>
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#responseHeaderTab" type="button" role="tab" aria-controls="responseHeader" aria-selected="false">Header</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content border-bottom" style="min-height: 250px;">
|
||||
@@ -365,6 +380,32 @@
|
||||
target.find('.path').val(model.path);
|
||||
|
||||
},
|
||||
renderVariables: function (tabIdx) {
|
||||
let target = $('#api_request_' + tabIdx);
|
||||
target.find('.variables').empty();
|
||||
|
||||
let model = apiRequests[tabIdx];
|
||||
for (let i = 0; i < model.variables.length; i++) {
|
||||
let template = $('#inputTemplate').children().find('tr').clone();
|
||||
if (model.variables[i].enabled) {
|
||||
template.find('input[name="enabled"]').prop("checked", model.variables[i].enabled);
|
||||
}
|
||||
template.find('input[name="key"]').val(model.variables[i].key);
|
||||
template.find('input[name="value"]').val(model.variables[i].value);
|
||||
template.find('button').attr("data-id", i);
|
||||
|
||||
template.find('input[name="enabled"]').on('change', function () {
|
||||
model.variables[i].enabled = $(this).prop('checked');
|
||||
});
|
||||
template.find('input[name="key"]').on('input', function () {
|
||||
model.variables[i].key = $(this).val();
|
||||
});
|
||||
template.find('input[name="value"]').on('input', function () {
|
||||
model.variables[i].value = $(this).val();
|
||||
});
|
||||
target.find('.variables').append(template);
|
||||
}
|
||||
},
|
||||
renderHeaders: function (tabIdx) {
|
||||
let target = $('#api_request_' + tabIdx);
|
||||
target.find('.request_headers').empty();
|
||||
@@ -437,9 +478,11 @@
|
||||
template.attr('class', 'tab-pane fade mt-1' + (idx === this.currentIdx ? ' show active' : ''));
|
||||
template.find('.btn_request_param_tab').attr('data-bs-target', "#requestParamTab_" + idx);
|
||||
template.find('.btn_request_header_tab').attr('data-bs-target', "#requestHeaderTab_" + idx);
|
||||
template.find('.btn_variables_tab').attr('data-bs-target', "#variablesTab_" + idx);
|
||||
template.find('.btn_request_body_tab').attr('data-bs-target', "#requestBodyTab_" + idx);
|
||||
|
||||
template.find('.request_header_tab').attr('id', "requestHeaderTab_" + idx);
|
||||
template.find('.variables_tab').attr('id', "variablesTab_" + idx);
|
||||
template.find('.request_param_tab').attr('id', "requestParamTab_" + idx);
|
||||
template.find('.request_body_tab').attr('id', "requestBodyTab_" + idx);
|
||||
template.find('.api_name').text(model.name);
|
||||
@@ -455,6 +498,10 @@
|
||||
controller.addQueryParam(idx, '', '');
|
||||
});
|
||||
|
||||
target.find('.btn_add_variables').click(function () {
|
||||
controller.addVariable(idx, '', '');
|
||||
});
|
||||
|
||||
target.find('input[name="basePath"]').val(target.find('select[name="server"] option:selected').data('path'));
|
||||
target.find('select[name="server"]').val(model.server);
|
||||
target.find('select[name="server"]').on('change', function () {
|
||||
@@ -479,6 +526,12 @@
|
||||
}
|
||||
});
|
||||
|
||||
target.find('.variables').on('click', 'button', function () {
|
||||
if ($(this).hasClass('btn_remove')) {
|
||||
controller.removeVariable(idx, $(this).data("id"));
|
||||
}
|
||||
});
|
||||
|
||||
target.find('.path').on('input', function () {
|
||||
model.path = $(this).val();
|
||||
model.queryParams = [];
|
||||
@@ -536,6 +589,7 @@
|
||||
target.find('.method').val(model.method);
|
||||
this.renderParam(idx);
|
||||
this.renderHeaders(idx);
|
||||
this.renderVariables(idx);
|
||||
this.openTab(view.currentIdx);
|
||||
},
|
||||
render: function () {
|
||||
@@ -681,6 +735,20 @@
|
||||
});
|
||||
view.renderParam(tabIdx);
|
||||
},
|
||||
addVariable: function (tabIdx, key, value) {
|
||||
let model = apiRequests[tabIdx];
|
||||
model.variables.push({
|
||||
key: key,
|
||||
value: value
|
||||
});
|
||||
view.renderVariables(tabIdx);
|
||||
},
|
||||
removeVariable: function (tabIdx, idx) {
|
||||
let model = apiRequests[tabIdx];
|
||||
model.variables.splice(idx, 1);
|
||||
this.buildPath(tabIdx);
|
||||
view.renderVariables(tabIdx);
|
||||
},
|
||||
buildPath: function (tabIdx) {
|
||||
let model = apiRequests[tabIdx];
|
||||
let queryString = model.path.split('?')[0];
|
||||
@@ -861,6 +929,7 @@
|
||||
path: '',
|
||||
headers: [],
|
||||
queryParams: [],
|
||||
variables: [],
|
||||
requestBody: '',
|
||||
collectionId : collectionId,
|
||||
responseModel: {
|
||||
|
||||
Reference in New Issue
Block a user