Add ability to test http functions with postman like interface

This commit is contained in:
Peter Stockings
2023-12-16 19:55:51 +11:00
parent 8f94ae12ef
commit ab25d557f8
5 changed files with 86 additions and 96 deletions

14
app.py
View File

@@ -5,7 +5,7 @@ from jinja2_fragments import render_block
from flask_htmx import HTMX
import requests
from db import DataBase
from services import create_http_functions_view_model
from services import create_http_function_view_model, create_http_functions_view_model
app = Flask(__name__)
app.config.from_pyfile('config.py')
@@ -32,6 +32,7 @@ DEFAULT_SCRIPT = """async (req) => {
<td>${value}</td>
</tr>`)}
</table>
<pre>${JSON.stringify(req.body, null, 2)}</pre>
</div>`)
}"""
@@ -59,9 +60,14 @@ def map_isolator_response_to_flask_response(response):
def home():
return render_template("home.html", script=DEFAULT_SCRIPT)
@ app.route("/client", methods=["GET"])
def client():
return render_template("client.html")
@ app.route("/client/<function>", methods=["GET"])
def client(function):
http_function = db.get_http_function(function)
if not http_function:
return jsonify({'error': 'Function not found'}), 404
http_function = create_http_function_view_model(http_function)
return render_template("client.html", **http_function)
@ app.route("/dashboard", methods=["GET"])
def dashboard():

View File

@@ -1,18 +1,25 @@
def create_http_function_view_model(http_function):
# Base URL for the function invocation
base_url = "https://function.peterstockings.com/f/"
name = http_function['name']
function_view_model = {
"id": http_function['id'],
"name": name,
"script_content": http_function['script_content'],
"url": f"{base_url}{name}",
"invoke_count": http_function['invoked_count']
}
return function_view_model
def create_http_functions_view_model(http_functions):
# Base URL for the function invocation
base_url = "https://function.peterstockings.com/f/"
view_model = []
for function in http_functions:
name = function['name']
function_view_model = {
"id": function['id'],
"name": name,
"script_content": function['script_content'],
"url": f"{base_url}{name}",
"invoke_count": function['invoked_count']
}
function_view_model = create_http_function_view_model(function)
view_model.append(function_view_model)
return view_model

View File

@@ -4,7 +4,8 @@
<div class="mx-auto w-full">
<form class="flex"><select
class="px-4 py-2 border rounded-md border-gray-300 hover:border-orange-500 focus:outline-none bg-gray-100">
class="px-4 py-2 border rounded-md border-gray-300 hover:border-orange-500 focus:outline-none bg-gray-100"
name="method">
<option value="GET">GET</option>
<option value="POST">POST</option>
<option value="PUT">PUT</option>
@@ -12,22 +13,22 @@
<option value="DELETE">DELETE</option>
</select><input
class="ml-3 w-full px-4 py-2 border rounded-md border-gray-300 hover:border-orange-500 focus:outline-orange-500"
value="https://function.peterstockings.com/f/helloworld"><button
class="ml-3 px-6 py-2 rounded-md font-semibold text-white bg-orange-500 hover:bg-orange-600"
type="button">Send</button></form>
name="url" value="{{ url }}"><button
class="ml-3 px-6 py-2 rounded-md font-semibold text-white bg-orange-500 hover:bg-orange-600" type="button"
id="send-request">Send</button></form>
<div class="react-tabs" data-rttabs="true">
<ul class="flex mt-5 border border-gray-300 rounded-t-lg" role="tablist">
<li class="mr-3 py-2 px-4 border-orange-400 focus:outline-none
hover:text-orange-500 cursor-pointer border-b-2 text-orange-600" role="tab" id="tab:r0:0" aria-selected="true"
aria-disabled="false" aria-controls="panel:r0:0" tabindex="0" data-rttab="true">Query Params</li>
hover:text-orange-500 cursor-pointer" role="tab" id="tab:r0:0" aria-selected="true" aria-disabled="false"
aria-controls="panel:r0:0" tabindex="0" data-rttab="true">Query Params</li>
<li class="mr-3 py-2 px-4 border-orange-400 focus:outline-none
hover:text-orange-500 cursor-pointer" role="tab" id="tab:r0:1" aria-selected="false" aria-disabled="false"
aria-controls="panel:r0:1" data-rttab="true">Headers</li>
<li class="mr-3 py-2 px-4 border-orange-400 focus:outline-none
hover:text-orange-500 cursor-pointer" role="tab" id="tab:r0:2" aria-selected="false" aria-disabled="false"
aria-controls="panel:r0:2" data-rttab="true">Body</li>
hover:text-orange-500 cursor-pointer border-b-2 text-orange-600" role="tab" id="tab:r0:2"
aria-selected="false" aria-disabled="false" aria-controls="panel:r0:2" data-rttab="true">Body</li>
</ul>
<div class="react-tabs__tab-panel px-4 py-4 rounded-b-lg border border-t-0 border-gray-300 react-tabs__tab-panel--selected"
<div class="react-tabs__tab-panel px-4 py-4 rounded-b-lg border border-t-0 border-gray-300 react-tabs__tab-panel--selected hidden"
role="tabpanel" id="panel:r0:0" aria-labelledby="tab:r0:0">
<div class="">
<div class="flex mb-3"><input
@@ -40,8 +41,8 @@
class="px-6 py-1 rounded-md text-orange-600 border border-orange-400 hover:bg-orange-100">Add</button>
</div>
</div>
<div class="react-tabs__tab-panel px-4 py-4 rounded-b-lg border border-t-0 border-gray-300" role="tabpanel"
id="panel:r0:1" aria-labelledby="tab:r0:1">
<div class="react-tabs__tab-panel px-4 py-4 rounded-b-lg border border-t-0 border-gray-300 hidden"
role="tabpanel" id="panel:r0:1" aria-labelledby="tab:r0:1">
<div class="">
<div class="flex mb-3"><input
class="px-4 py-1.5 w-full border border-gray-300 rounded-md hover:border-orange-500 focus:outline-orange-500"
@@ -56,37 +57,10 @@
<div class="react-tabs__tab-panel px-4 py-4 rounded-b-lg border border-t-0 border-gray-300" role="tabpanel"
id="panel:r0:2" aria-labelledby="tab:r0:2">
<div>
<div class="cm-editor cm-wrap ͼ1 ͼ2 ͼ4">
<div aria-live="polite" style="position: absolute; top: -10000px;"></div>
<div tabindex="-1" class="cm-scroller">
<div class="cm-gutters" aria-hidden="true" style="position: sticky; min-height: 42px;">
<div class="cm-gutter cm-lineNumbers">
<div class="cm-gutterElement"
style="height: 0px; visibility: hidden; pointer-events: none;">9</div>
<div class="cm-gutterElement cm-activeLineGutter" style="height: 14px;">1</div>
<div class="cm-gutterElement" style="height: 14px;">2</div>
<div class="cm-gutterElement" style="height: 14px;">3</div>
</div>
<div class="cm-gutter cm-foldGutter">
<div class="cm-gutterElement"
style="height: 0px; visibility: hidden; pointer-events: none;"><span
title="Unfold line"></span></div>
<div class="cm-gutterElement cm-activeLineGutter" style="height: 14px;"></div>
</div>
</div>
<div spellcheck="false" autocorrect="off" autocapitalize="off" contenteditable="true"
class="cm-content" style="tab-size: 2" role="textbox" aria-multiline="true"
aria-autocomplete="list">
<div class="cm-activeLine cm-line">{</div>
<div class="cm-line"> </div>
<div class="cm-line">}</div>
</div>
<div class="cm-selectionLayer" aria-hidden="true"></div>
<div class="cm-cursorLayer" aria-hidden="true" style="animation-duration: 1200ms;">
<div class="cm-cursor cm-cursor-primary" style="left: 0px; top: 0px; height: 0px;"></div>
</div>
</div>
</div>
<textarea id="request-body" rows="4"
class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder="Request body"></textarea>
</div>
</div>
</div>
@@ -103,41 +77,9 @@
<div class="px-4 py-4 rounded-b-lg border border-t-0 border-gray-300">
<div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel:r1:0"
aria-labelledby="tab:r1:0">
<div>
<div class="cm-editor cm-wrap ͼ1 ͼ2 ͼ4">
<div aria-live="polite" style="position: absolute; top: -10000px;"></div>
<div tabindex="-1" class="cm-scroller">
<div class="cm-gutters" aria-hidden="true"
style="position: sticky; min-height: 26.1979px;">
<div class="cm-gutter cm-lineNumbers">
<div class="cm-gutterElement"
style="height: 0px; visibility: hidden; pointer-events: none;">9</div>
<div class="cm-gutterElement cm-activeLineGutter"
style="height: 18.1979px; margin-top: 4px;">1</div>
<code id="response"></code>
</div>
<div class="cm-gutter cm-foldGutter">
<div class="cm-gutterElement"
style="height: 0px; visibility: hidden; pointer-events: none;"><span
title="Unfold line"></span></div>
<div class="cm-gutterElement cm-activeLineGutter"
style="height: 18.1979px; margin-top: 4px;"></div>
</div>
</div>
<div spellcheck="false" autocorrect="off" autocapitalize="off" contenteditable="false"
class="cm-content" style="tab-size: 2" role="textbox" aria-multiline="true"
aria-autocomplete="list">
<div class="cm-activeLine cm-line">{}</div>
</div>
<div class="cm-selectionLayer" aria-hidden="true"></div>
<div class="cm-cursorLayer" aria-hidden="true" style="animation-duration: 1200ms;">
<div class="cm-cursor cm-cursor-primary"
style="left: 33.8229px; top: 5.33334px; height: 15.3333px;"></div>
</div>
</div>
</div>
</div>
</div>
<div class="react-tabs__tab-panel" role="tabpanel" id="panel:r1:1" aria-labelledby="tab:r1:1">
<div class="react-tabs__tab-panel hidden" role="tabpanel" id="panel:r1:1" aria-labelledby="tab:r1:1">
<table class="text-left">
<thead>
<tr>
@@ -153,4 +95,34 @@
</div>
</div>
<script>
(function () {
const send_request_btn = document.getElementById('send-request');
const response = document.getElementById('response');
send_request_btn.addEventListener('click', () => {
const url = document.querySelector('input[name="url"]').value;
const method = document.querySelector('select[name="method"]').value;
let body = document.getElementById('request-body').value;
// If get or head then dont add body
if (method === 'GET' || method === 'HEAD') {
body = null;
}
fetch(url, {
method,
body,
headers: {
'Content-Type': 'application/json'
}
}).then(response => {
response.text().then(text => {
response.innerHTML = text;
});
});
})
})();
</script>
{% endblock %}

View File

@@ -1,8 +1,7 @@
<div class="flex items-center" data-id="51">
<h1 class="font-semibold text-lg md:text-2xl" data-id="52">HTTP functions</h1>
<button
class="inline-flex items-center justify-center text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-9 rounded-md px-3 ml-auto"
hx-get="{{ url_for('client') }}" hx-target="#container" hx-swap="innerHTML">
class="inline-flex items-center justify-center text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-9 rounded-md px-3 ml-auto">
Add Function
</button>
</div>
@@ -41,10 +40,17 @@
</td>
<td class="p-4 align-middle [&amp;:has([role=checkbox])]:pr-0 hidden md:table-cell" data-id="68">
<button
class="inline-flex items-center justify-center text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-9 rounded-md px-3 mr-2"
data-id="69">Edit</button><button
class="inline-flex items-center justify-center text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-9 rounded-md px-3"
data-id="70">Delete</button>
data-id="69" hx-get="{{ url_for('client', function=function.name) }}" hx-target="#container"
hx-swap="innerHTML">
Try
</button>
<button
class="inline-flex items-center justify-center text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-9 rounded-md px-3"
data-id="69" hx-get="{{ url_for('client', function=function.name) }}" hx-target="#container"
hx-swap="innerHTML">
Edit
</button>
</td>
</tr>
{% endfor %}

View File

@@ -1,8 +1,7 @@
<div class="flex items-center" data-id="51">
<h1 class="font-semibold text-lg md:text-2xl" data-id="52">Timer functions</h1>
<button
class="inline-flex items-center justify-center text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-9 rounded-md px-3 ml-auto"
hx-get="{{ url_for('client') }}" hx-target="#container" hx-swap="innerHTML">
class="inline-flex items-center justify-center text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-9 rounded-md px-3 ml-auto">
Add Function
</button>
</div>