Public
Edited
Dec 20, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
await visibility();

// Constants
const endpointKey = "EXAMPLE_1";

// Step 1: Create a local function returning files when a new HTTP request arrives:
const httpHandler = async (request) => {
return new Response("Hello World!");
};

// Step 2: Start a ServiceWorker and open a MessageChannel used to recieve HTTP requests and send responses:
const {
port,
baseUrl,
close: closeChannel
} = await WebRunHttp.newRemoteRelayChannel();
invalidation.then(closeChannel);
const serviceUrl = new URL(`~${endpointKey}/`, baseUrl);

// Step 3: Instantiate a "server" using the communcation channel with the ServiceWorker:
const close = await WebRunHttp.initHttpService(httpHandler, {
key: endpointKey,
port
});
invalidation.then(close);

const endpointUrl = `${serviceUrl}/index.html`;
const label = `/~${endpointKey}/index.html`;
return renderIframe(endpointUrl, label);
}
Insert cell
Insert cell
Insert cell
{
// await visibility();

// Name of the second endpoint
const endpointKey = "ENDPOINT_EXAMPLE_2";

// -----------------
// Start the ServiceWorker and open a communication port:
const {
port,
baseUrl,
close: closeChannel
} = await WebRunHttp.newRemoteRelayChannel();
invalidation.then(closeChannel);

// -----------------
// Define the base URL for this service:
const serviceBaseUrl = `${baseUrl}~${endpointKey}`;

// -----------------
// Define an HTTP handler. In this case it is a simple file dispatcher
// returning file content by path.
const httpHandler = async (request) => {
const url = request.url;

// To get the path from URL we need to remove the service prefix:
const path = url.slice(serviceBaseUrl.length);

// Get the file by the corresponding path:
const file = files[path];

// Send 404 if nothing was found:
if (!file) {
return new Response(`Error 404: File Not Found. Path: '${path}'.`, {
status: 404,
statusText: "File not found"
});
}

// Return the file content with the corresponding MIME type:
return new Response(file.content, {
headers: {
status: 200,
"Content-Type": file.mimeType
}
});
};

// -----------------
// Register a new HTTP service using the communication port defined above:
const close = await WebRunHttp.initHttpService(httpHandler, {
key: endpointKey,
port
});
invalidation.then(close);

// -----------------
// And finally we can create an iframe element visualizing the page:
const endpointUrl = `${serviceBaseUrl}/index.html`;
const label = `/~${endpointKey}/index.html`;
return renderIframe(endpointUrl, label);
}
Insert cell
Insert cell
{
await visibility();

// Name of the second endpoint
const endpointKey = "ENDPOINT_EXAMPLE_3";

// -----------------
// Start the ServiceWorker and open a communication port:
const {
port,
baseUrl,
close: closeChannel
} = await WebRunHttp.newRemoteRelayChannel();
invalidation.then(closeChannel);

// -----------------
// Define the base URL for this service:
const serviceBaseUrl = `${baseUrl}~${endpointKey}`;

// -----------------
// This "database" is used to store submitted data:
let data = {
firstName: "John",
lastName: "Smith"
};
const div = htl.html`<div>`;
function updateDiv() {
div.innerText = JSON.stringify(data);
}
updateDiv();
// -----------------
// Request dispatcher.
const httpHandler = async (request) => {
const { url, method } = request;
const path = url.slice(serviceBaseUrl.length);
if (method === "POST") {
const f = await request.formData();
for (const [name, value] of f.entries()) {
data[name] = value;
}
updateDiv();
return replyWithHtmlPage(`
<h3>Success!</h3>
<p>Recieved data:</p>
<pre>${JSON.stringify(data, null, 2)}</pre>
<p>Return <a href="./index.html">back</a>.</p>
`);
} else if (method === "GET") {
return replyWithHtmlPage(`
<h3>Submit Form</h3>

<form action="./post" method="post" enctype="multipart/form-data">
<div>
<label>
First Name:
<input name="firstName" type="text" value=${JSON.stringify(
data.firstName
)}></input>
</label>
</div>
<div>
<label>
Last Name:
<input name="lastName" type="text" value=${JSON.stringify(
data.lastName
)}></input>
</label>
</div>
<input type="submit" value="Go!"></input>
</form>

<p>
Click <a href="./index.html">here to refresh this page</a>.
</p>

`);
}
};

const close = await WebRunHttp.initHttpService(httpHandler, {
key: endpointKey,
port
});
invalidation.then(close);

const endpointUrl = `${serviceBaseUrl}/index.html`;
const label = `/~${endpointKey}/index.html`;
const iframe = renderIframe(endpointUrl, label);

return htl.html`<div>${div}${iframe}`;

// --------------------

function replyWithHtmlPage(content) {
return new Response(
`<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
${content}
</body>
</html>
`,
{
status: 200,
headers: {
"Content-Type": "text/html"
}
}
);
}
}
Insert cell
function renderIframe(url, label) {
return htl.html`<div>
<iframe src="${url}" width="100%" height="250" style="border: 1px solid gray; outline: none; width: 100%; height: 300px;"></iframe>
</div>`;
}
Insert cell
Insert cell
WebRunHttp = import(
"https://unpkg.com/@statewalker/webrun-http-browser@0.3/dist/index.js"
)
Insert cell
import { toc } from "@nebrius/indented-toc"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more