lean-api/view/lean-api/request_debugger.phtml
2025-10-06 17:28:08 +00:00

245 lines
9.0 KiB
PHTML

{% use Ulmus\Api\Common\MethodEnum %}
{% language.set "lean.api.request.debugger" %}
<div id="request-debugger" class="hide">
<div class="request-head">
<div class="method" style="">
{% ui.select "method", MethodEnum::generateArray(), post('method') %}
</div>
<div class="url" style="flex-grow: 1;">
{% ui:text "url" %}
{% ui:text "token", $this->session->jwt %}
<button class="request-btn">Envoyer</button>
</div>
</div>
<div class="request-content">
<div id="request" style="min-height: 150px; width:100%; border:1px solid #ededed;">{}</div>
</div>
<div class="request-response hide">
<hr>
<pre id="response" class="code" ace-theme="ace/theme/cloud9_day"></pre>
<div class="response-head">
<span class="response-code"></span>
<span class="response-message"></span>
</div>
</div>
</div>
<style>
.request-head {display:flex;padding-top: 4px;border:1px solid #e1e1e1;border-bottom:0}
.request-head .method {width: 90px;text-align: center;line-height: 34px;font-weight: bold;}
.request-head .method select {background:none;border:0;font-size: inherit;text-align: center;color: inherit;font-weight: bold;}
.request-head .url input {border:0;color: #6f6f6f;background: #f9f9f9;font-size: 80%;font-weight: bold;}
.request-head .url [name="url"] {width: calc(65% - 80px);}
.request-head .url [name="token"] {width:calc(35% - 10px);font-size:60%}
.request-head .url button {font-size: 80%;width: 80px;border-radius:0;border: 1px solid #ccc;height:26px;padding: 0;background:#f9f9f9;color: #6f6f6f;cursor: pointer;}
.request-head .url button:active {filter:contrast(85%);}
.response-head {display: flex;border:1px solid #9f9f9f;margin-bottom: 5px;}
.response-head .response-code {background:#dfdfdf;padding:0 5px;font-weight: bold;line-height: 29px;font-size: 80%;}
.response-head .response-message {padding:0 10px;background:#fbfbfb;line-height: 30px;font-size: 80%;}
#response {max-height: 66vh;}
</style>
<script src="{% asset 'static/ace/src-noconflict/ace.js' %}" type="text/javascript" charset="utf-8"></script>
<script src="{% asset 'static/ace/src-noconflict/ext-static_highlight.js' %}" type="text/javascript" charset="utf-8"></script>
<script>
let requestDebugger = document.getElementById('request-debugger'),
requestHead = requestDebugger.querySelector(".request-head"),
requestContent = requestDebugger.querySelector(".request-content"),
responseHead = requestDebugger.querySelector(".response-head"),
responseResponse = requestDebugger.querySelector(".request-response"),
method = requestHead.querySelector(".method"),
input = requestHead.querySelector("[name='url']"),
token = requestHead.querySelector("[name='token']"),
button = requestHead.querySelector(".request-btn");
// Editor
let editor = ace.edit("request");
editor.setTheme("ace/theme/cloud9_day");
editor.session.setMode("ace/mode/json");
// Code highlighter
let highlight = ace.require("ace/ext/static_highlight"),
dom = ace.require("ace/lib/dom"),
responseEditorElement = responseResponse.querySelector('#response');
input.addEventListener('keydown', evt => evt.keyCode === 13 ? button.click() : null);
document.addEventListener("DOMContentLoaded", (evt) => {
document.querySelectorAll(".form-name").forEach(elem => {
elem.insertAdjacentHTML('beforeend', '<a href="javascript:void(0)" class="btn debug">DEBUG</a>');
let formData = JSON.parse(elem.closest('.single-form').getAttribute('data-form'));
elem.querySelector(".btn.debug").addEventListener("click", (btn) => {
requestDebugger.classList.toggle('hide', false);
let json = {};
formData.fields.forEach((field) => {
json[field.name] = field.allowNulls ? null : "";
});
editor.setValue(JSON.stringify(json,null,2), -1);
});
});
document.querySelectorAll("li[class*='method-']").forEach( (url) => {
url.addEventListener("click", (evt) => {
evt.preventDefault();
let routeMethod = url.querySelector('.route-method');
method.style.color = getComputedStyle(routeMethod).getPropertyValue('background-color');
method.querySelector('select').value = routeMethod.innerText;
input.value = url.querySelector('.route-link a').getAttribute('href');
document.getElementById('request-debugger').classList.toggle('hide', false);
replaceUrlVariableUsingData();
input.focus();
});
});
let aceMode;
button.addEventListener("click", (evt) => {
let requestMethod = method.querySelector('select').value;
if (requestMethod === 'DELETE' && ! confirm("Attention ! Vous allez lancer une procédure de suppression de données.\n\nContinuer ?")) {
return;
}
launchRequest(requestMethod, input.value, editor.getValue())
.then((response) => {
responseHead.querySelector('.response-code').innerText = response.status;
responseHead.querySelector('.response-message').innerText = response.statusText;
aceMode = parseContentType(response);
return response.text();
})
.then(body => {
if (aceMode === "json") {
body = JSON.stringify(JSON.parse(body), null, 2);
responseEditorElement.innerHTML = body;
}
else {
responseEditorElement.innerText = body;
}
formatResponse("ace/mode/" + aceMode);
});
responseResponse.classList.toggle('hide', false);
});
let selectRoute = getQueryVariable("debug.route"),
presetData = getQueryVariable("debug.data");
if ( selectRoute ) {
if (presetData) {
editor.setValue(presetData);
}
document.querySelector(`[data-name="${selectRoute}"]`).click();
}
});
async function launchRequest(method = "POST", url = "", body = "{}") {
method = method.toUpperCase();
let responseData = {
method: method,
mode: "cors",
cache: "no-cache",
credentials: "omit",
headers: {
"Content-Type": "application/json",
'Authorization': `Bearer ${token.value}`
},
redirect: "follow",
referrerPolicy: "no-referrer"
};
if ( [ "HEAD", "GET" ].indexOf(method) === -1 ) {
responseData.body = body;
}
return await fetch(url, responseData);
}
function formatResponse(mode) {
highlight(responseEditorElement, {
mode: mode,
theme: responseEditorElement.getAttribute("ace-theme"),
firstLineNumber: 1,
showGutter: responseEditorElement.getAttribute("ace-gutter"),
trim: true
});
}
function parseContentType(response) {
let type = response.headers.get('content-type').toLowerCase();
if ( type.indexOf('text/html') !== -1 ) {
return "html";
}
else if ( type.indexOf('text/css') !== -1 ) {
return "css";
}
else if ( type.indexOf('text/csv') !== -1 ) {
return "csv";
}
else if ( type.indexOf('text/xml') !== -1 ) {
return "xml";
}
else if ( type.indexOf('text/plain') !== -1 ) {
return "text";
}
else if ( type.indexOf('application/javascript') !== -1 ) {
return "javascript";
}
else if ( type.indexOf('application/json') !== -1 || type.indexOf('application/ld+json') !== -1 ) {
return "json";
}
}
function getQueryVariable(variable) {
retval = false;
window.location.search.substring(1).split("&").forEach(vars => {
var pair = vars.split("=");
if (pair.length === 2 && pair[0] === variable) {
return retval = decodeURI(pair[1]);
}
});
return retval;
}
function replaceUrlVariableUsingData() {
try {
let vars = input.value.match(/[^{}]+(?=})/g),
body = JSON.parse(editor.getValue());
vars.forEach(v => {
if (body[v]) {
input.value = input.value.replace("{" + v + "}", body[v]);
}
})
}
catch(e) {}
}
</script>