Skip to content

Commit 1f1c070

Browse files
committed
POC: Add request form builder
1 parent fc7fdac commit 1f1c070

File tree

9 files changed

+158
-87
lines changed

9 files changed

+158
-87
lines changed

assets/css/v2/style.css

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,9 +1432,43 @@ hr {
14321432

14331433
/* NJS Hackathon stuff */
14341434
.request-builder {
1435-
height: 20rem;
1436-
width: var(--grid-content);
1437-
border: 1px solid #cccccc;
1435+
input,
1436+
select,
1437+
textarea {
1438+
width: 100%;
1439+
padding: 6px;
1440+
margin-top: 5px;
1441+
margin-bottom: 15px;
1442+
}
1443+
.header-row {
1444+
display: flex;
1445+
}
1446+
.header-row input {
1447+
margin-right: 5px;
1448+
flex: 1;
1449+
}
1450+
button {
1451+
height: 29px;
1452+
margin-top: 5px;
1453+
background-color: white;
1454+
border: 1px solid black;
1455+
padding: 4px 6px;
1456+
cursor: pointer;
1457+
font-size: 12px;
1458+
color: #000;
1459+
z-index: 1;
1460+
--color-codeblock-shadow: 0% 0 0;
1461+
box-shadow: 0px 2px 0px oklch(var(--color-codeblock-shadow) / 0.15);
1462+
}
1463+
1464+
button:hover {
1465+
box-shadow: 0px 2px 0px oklch(0.65 0.188 24 / 0.3);
1466+
}
1467+
1468+
button:focus {
1469+
outline: none;
1470+
box-shadow: 0px 2px 0px oklch(0.65 0.188 24 / 0.8);
1471+
}
14381472
}
14391473

14401474
.njs-function {

exampleSite/content/njs/basic-example.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ weight: 100
77

88
To use njs in nginx:
99
- [install](https://nginx.org/en/docs/njs/install.html) njs scripting language
10-
- create an njs script file, for example, http.js. See [reference](Reference) for the list of njs properties and methods.
10+
1111

1212
```nginx
1313
load_module modules/ngx_http_js_module.so;
@@ -28,4 +28,4 @@ http {
2828
```
2929

3030

31-
{{< njs-playground exampleRequest=exampleRequest.js exampleNJS=greet.js fnName=hello >}}
31+
{{< njs-playground exampleNJS=greet.js fnName=hello >}}

exampleSite/content/njs/echo-server.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ title: Echo Server
44
weight: 100
55
---
66

7-
## Basic Example
8-
To use njs in nginx:
9-
- [install](https://nginx.org/en/docs/njs/install.html) njs scripting language
10-
- create an njs script file, for example, http.js. See [reference](Reference) for the list of njs properties and methods.
7+
This example demonstrates how to create a simple echo endpoint.
8+
The endpoint returns the details of the request sent to NGINX as JSON.
119

1210
```nginx
1311
load_module modules/ngx_http_js_module.so;
@@ -28,4 +26,4 @@ http {
2826
```
2927

3028

31-
{{< njs-playground exampleRequest=exampleRequestEcho.js exampleNJS=echo.js fnName=echo >}}
29+
{{< njs-playground exampleNJS=echo.js fnName=echo >}}

exampleSite/static/njs/echo.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@ function echo(r) {
99
requestText,
1010
} = r;
1111

12-
// Get request body (if applicable)
13-
let body = "";
14-
if (requestBuffer !== "" || !Array.isArray(requestBuffer)) {
15-
body = Buffer.from(requestBuffer).toString();
16-
}
17-
1812
// Construct the echo response (JSON format)
1913
const response = {
2014
method,
@@ -26,7 +20,7 @@ function echo(r) {
2620
version: httpVersion,
2721
};
2822

29-
r.return(200, JSON.stringify(response));
23+
return r.return(200, JSON.stringify(response));
3024
}
3125

3226
// uncomment for us in NJS

exampleSite/static/njs/exampleRequest.js

Lines changed: 0 additions & 17 deletions
This file was deleted.

exampleSite/static/njs/exampleRequestEcho.js

Lines changed: 0 additions & 17 deletions
This file was deleted.

exampleSite/static/njs/requestConverter.js

Lines changed: 0 additions & 7 deletions
This file was deleted.

layouts/partials/njs-playground.html

Lines changed: 115 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
<h3>Request Builder</h3>
2-
<div class="request-builder" id="request-builder"></div>
2+
<div class="request-builder">
3+
<label for="method">HTTP Method:</label>
4+
<select id="method">
5+
<option value="GET">GET</option>
6+
<option value="POST">POST</option>
7+
<option value="PUT">PUT</option>
8+
<option value="DELETE">DELETE</option>
9+
<option value="PATCH">PATCH</option>
10+
<option value="OPTIONS">OPTIONS</option>
11+
<option value="HEAD">HEAD</option>
12+
</select>
13+
14+
<label for="url">URI:</label>
15+
<input id="url" type="text" placeholder="/echo">
16+
17+
<label for="bodyJSON">JSON Body:</label>
18+
<textarea id="bodyJSON" rows="8" placeholder='{"example":"value"}'></textarea>
19+
20+
<label>Headers:</label>
21+
<div id="headers-container">
22+
<!-- Dynamic header entries go here -->
23+
</div>
24+
<button id="add-header">Add Header</button>
25+
26+
</div>
327
<h3>NJS Function</h3>
428
<div class="njs-function" id="editor"></div>
529
<button id="run-btn">Simulate Request</button>
@@ -12,29 +36,83 @@ <h3>NJS Function</h3>
1236
<script type="module">
1337
import { getQuickJS } from "https://esm.sh/[email protected]";
1438

15-
// Fetch the example js files, set by shortcode usage
16-
const exampleResponse = await fetch("/njs/{{ .exampleRequest }}");
17-
if (!exampleResponse.ok) {
18-
throw new Error(`Failed to fetch {{ .exampleRequest }}: ${exampleResponse.status}`);
39+
// Request builder stuff
40+
const methodEl = document.getElementById('method');
41+
const urlEl = document.getElementById('url');
42+
const bodyEl = document.getElementById('bodyJSON');
43+
const headersContainerEl = document.getElementById('headers-container');
44+
const addHeaderBtn = document.getElementById('add-header');
45+
debugger;
46+
// Initialize headers with one empty pair
47+
addHeaderField();
48+
49+
addHeaderBtn.addEventListener('click', addHeaderField);
50+
51+
function addHeaderField() {
52+
const headerDiv = document.createElement('div');
53+
headerDiv.className = 'header-row';
54+
55+
const keyInput = document.createElement('input');
56+
keyInput.type = 'text';
57+
keyInput.placeholder = 'Header Name (e.g., Content-Type)';
58+
59+
const valueInput = document.createElement('input');
60+
valueInput.type = 'text';
61+
valueInput.placeholder = 'Header Value (e.g., application/json)';
62+
63+
const removeBtn = document.createElement('button');
64+
removeBtn.textContent = 'X';
65+
removeBtn.type = 'button';
66+
removeBtn.onclick = () => headersContainerEl.removeChild(headerDiv);
67+
68+
headerDiv.appendChild(keyInput);
69+
headerDiv.appendChild(valueInput);
70+
headerDiv.appendChild(removeBtn);
71+
72+
headersContainerEl.appendChild(headerDiv);
73+
}
74+
75+
function buildRequestObject() {
76+
const headers = {};
77+
const headerRows = headersContainerEl.querySelectorAll('.header-row');
78+
79+
headerRows.forEach(row => {
80+
const inputs = row.querySelectorAll('input');
81+
const key = inputs[0].value.trim();
82+
const val = inputs[1].value.trim();
83+
if (key && val) {
84+
headers[key] = val;
85+
}
86+
});
87+
88+
let bodyContent;
89+
try {
90+
bodyContent = bodyEl.value ? JSON.parse(bodyEl.value) : null;
91+
debugger;
92+
} catch (e) {
93+
alert('Invalid JSON in body');
94+
return;
95+
}
96+
97+
const requestObject = {
98+
method: methodEl.value,
99+
uri: urlEl.value,
100+
headersIn: headers,
101+
body: bodyContent
102+
};
103+
104+
return requestObject;
19105
}
20-
const exampleRequestCode = await exampleResponse.text();
106+
107+
//
21108

22109
const exampleNJSResponse = await fetch("/njs/{{ .exampleNJS }}");
23-
if (!exampleResponse.ok) {
110+
if (!exampleNJSResponse.ok) {
24111
throw new Error(`Failed to fetch {{ .exampleRequest }}: ${exampleNJSResponse.status}`);
25112
}
26113
const exampleNJSCode = await exampleNJSResponse.text();
27114

28-
const fnCaller = `
29-
const requestConverter = (request) => {
30-
return {
31-
...request,
32-
requestText: request.body,
33-
return: (status, value) => (JSON.stringify({status, value})),
34-
}
35-
}
36-
{{ .fnName }}(requestConverter(exampleRequest))
37-
`;
115+
38116

39117
(async () => {
40118
const QuickJS = await getQuickJS();
@@ -47,28 +125,38 @@ <h3>NJS Function</h3>
47125
editor = monaco.editor.create(document.getElementById("editor"), {
48126
value: exampleNJSCode,
49127
language: "javascript",
50-
theme
51-
});
52-
53-
requestBuilder = monaco.editor.create(document.getElementById("request-builder"), {
54-
value: exampleRequestCode,
55-
language: "javascript",
56-
theme
128+
theme,
129+
minimap: {
130+
enabled: false
131+
}
57132
});
58133
});
59134

60135

61-
62136
const runCode = async () => {
63137
const vm = QuickJS.newContext();
64138

65139
if (!vm) {
66140
alert("QuickJS is loading, please wait a moment.");
67141
return;
68142
}
69-
const requestSrc = requestBuilder.getValue();
143+
70144
const src = editor.getValue();
71-
const result = vm.evalCode(requestSrc + src + fnCaller);
145+
const requestObject = buildRequestObject();
146+
const fnCaller = `
147+
const exampleRequest = ${JSON.stringify(requestObject)};
148+
const requestConverter = (request) => {
149+
return {
150+
...request,
151+
requestText: request.body,
152+
return: (status, value) => (JSON.stringify({status, value})),
153+
}
154+
}
155+
{{ .fnName }}(requestConverter(exampleRequest))
156+
`;
157+
158+
159+
const result = vm.evalCode(src + fnCaller);
72160
const resultEl = document.getElementById("result");
73161

74162
if (result.error) {
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
{{ $exampleRequest := .Get "exampleRequest" }}
21
{{ $exampleNJS := .Get "exampleNJS" }}
32
{{ $fnName := .Get "fnName" }}
43
{{ partial "njs-playground.html" (
54
dict
6-
"exampleRequest" $exampleRequest
75
"exampleNJS" $exampleNJS
86
"fnName" $fnName
97
)}}

0 commit comments

Comments
 (0)