Add three new example scripts demonstrating the fswatch, sysinfo, and udp modules with file watching, system metrics, and UDP echo server/client patterns. Reorder the manual API sidebar navigation to list modules alphabetically, removing deprecated entries like websocket, tls, net, json, regex, jinja, os, signal, subprocess, sqlite, and timer while adding argparse, dataset, fswatch, and html.
569 lines
24 KiB
HTML
569 lines
24 KiB
HTML
<!DOCTYPE html>
|
|
<!-- retoor <retoor@molodetz.nl> -->
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>web - Wren-CLI Manual</title>
|
|
<link rel="stylesheet" href="../css/style.css">
|
|
</head>
|
|
<body>
|
|
<button class="mobile-menu-toggle">Menu</button>
|
|
<div class="container">
|
|
<aside class="sidebar">
|
|
<div class="sidebar-header">
|
|
<h1><a href="../index.html">Wren-CLI</a></h1>
|
|
<div class="version">v0.4.0</div>
|
|
</div>
|
|
<nav class="sidebar-nav">
|
|
<div class="section">
|
|
<span class="section-title">Getting Started</span>
|
|
<ul>
|
|
<li><a href="../getting-started/index.html">Overview</a></li>
|
|
<li><a href="../getting-started/installation.html">Installation</a></li>
|
|
<li><a href="../getting-started/first-script.html">First Script</a></li>
|
|
<li><a href="../getting-started/repl.html">Using the REPL</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="section">
|
|
<span class="section-title">Language</span>
|
|
<ul>
|
|
<li><a href="../language/index.html">Syntax Overview</a></li>
|
|
<li><a href="../language/classes.html">Classes</a></li>
|
|
<li><a href="../language/methods.html">Methods</a></li>
|
|
<li><a href="../language/control-flow.html">Control Flow</a></li>
|
|
<li><a href="../language/fibers.html">Fibers</a></li>
|
|
<li><a href="../language/modules.html">Modules</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="section">
|
|
<span class="section-title">API Reference</span>
|
|
<ul>
|
|
<li><a href="index.html">Overview</a></li>
|
|
<li><a href="string.html">String</a></li>
|
|
<li><a href="number.html">Num</a></li>
|
|
<li><a href="argparse.html">argparse</a></li>
|
|
<li><a href="base64.html">base64</a></li>
|
|
<li><a href="crypto.html">crypto</a></li>
|
|
<li><a href="dataset.html">dataset</a></li>
|
|
<li><a href="datetime.html">datetime</a></li>
|
|
<li><a href="dns.html">dns</a></li>
|
|
<li><a href="env.html">env</a></li>
|
|
<li><a href="fswatch.html">fswatch</a></li>
|
|
<li><a href="html.html">html</a></li>
|
|
<li><a href="http.html">http</a></li>
|
|
<li><a href="io.html">io</a></li>
|
|
<li><a href="jinja.html">jinja</a></li>
|
|
<li><a href="json.html">json</a></li>
|
|
<li><a href="markdown.html">markdown</a></li>
|
|
<li><a href="math.html">math</a></li>
|
|
<li><a href="net.html">net</a></li>
|
|
<li><a href="os.html">os</a></li>
|
|
<li><a href="pathlib.html">pathlib</a></li>
|
|
<li><a href="regex.html">regex</a></li>
|
|
<li><a href="scheduler.html">scheduler</a></li>
|
|
<li><a href="signal.html">signal</a></li>
|
|
<li><a href="sqlite.html">sqlite</a></li>
|
|
<li><a href="subprocess.html">subprocess</a></li>
|
|
<li><a href="sysinfo.html">sysinfo</a></li>
|
|
<li><a href="tempfile.html">tempfile</a></li>
|
|
<li><a href="timer.html">timer</a></li>
|
|
<li><a href="tls.html">tls</a></li>
|
|
<li><a href="udp.html">udp</a></li>
|
|
<li><a href="uuid.html">uuid</a></li>
|
|
<li><a href="wdantic.html">wdantic</a></li>
|
|
<li><a href="web.html" class="active">web</a></li>
|
|
<li><a href="websocket.html">websocket</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="section">
|
|
<span class="section-title">Tutorials</span>
|
|
<ul>
|
|
<li><a href="../tutorials/index.html">Tutorial List</a></li>
|
|
<li><a href="../tutorials/http-client.html">HTTP Client</a></li>
|
|
<li><a href="../tutorials/websocket-chat.html">WebSocket Chat</a></li>
|
|
<li><a href="../tutorials/database-app.html">Database App</a></li>
|
|
<li><a href="../tutorials/template-rendering.html">Templates</a></li>
|
|
<li><a href="../tutorials/cli-tool.html">CLI Tool</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="section">
|
|
<span class="section-title">How-To Guides</span>
|
|
<ul>
|
|
<li><a href="../howto/index.html">How-To List</a></li>
|
|
<li><a href="../howto/http-requests.html">HTTP Requests</a></li>
|
|
<li><a href="../howto/json-parsing.html">JSON Parsing</a></li>
|
|
<li><a href="../howto/regex-patterns.html">Regex Patterns</a></li>
|
|
<li><a href="../howto/file-operations.html">File Operations</a></li>
|
|
<li><a href="../howto/async-operations.html">Async Operations</a></li>
|
|
<li><a href="../howto/error-handling.html">Error Handling</a></li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
</aside>
|
|
<main class="content">
|
|
<nav class="breadcrumb">
|
|
<a href="../index.html">Home</a>
|
|
<span class="separator">/</span>
|
|
<a href="index.html">API Reference</a>
|
|
<span class="separator">/</span>
|
|
<span>web</span>
|
|
</nav>
|
|
|
|
<article>
|
|
<h1>web</h1>
|
|
|
|
<p>The <code>web</code> module provides a web framework for building HTTP servers and a client for making HTTP requests. It includes routing, middleware, sessions, static file serving, and class-based views.</p>
|
|
|
|
<pre><code>import "web" for Application, Router, Request, Response, View, Session, Client</code></pre>
|
|
|
|
<h2>Application Class</h2>
|
|
|
|
<div class="class-header">
|
|
<h3>Application</h3>
|
|
<p>HTTP server with routing and middleware</p>
|
|
</div>
|
|
|
|
<h3>Constructor</h3>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">Application.new</span>() → <span class="type">Application</span>
|
|
</div>
|
|
<p>Creates a new web application.</p>
|
|
|
|
<h3>Properties</h3>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">router</span> → <span class="type">Router</span>
|
|
</div>
|
|
<p>Access to the underlying router.</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">sessionStore</span> → <span class="type">SessionStore</span>
|
|
</div>
|
|
<p>Access to the session storage.</p>
|
|
|
|
<h3>Routing Methods</h3>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">get</span>(<span class="param">path</span>, <span class="param">handler</span>) → <span class="type">Application</span>
|
|
</div>
|
|
<div class="method-signature">
|
|
<span class="method-name">post</span>(<span class="param">path</span>, <span class="param">handler</span>) → <span class="type">Application</span>
|
|
</div>
|
|
<div class="method-signature">
|
|
<span class="method-name">put</span>(<span class="param">path</span>, <span class="param">handler</span>) → <span class="type">Application</span>
|
|
</div>
|
|
<div class="method-signature">
|
|
<span class="method-name">delete</span>(<span class="param">path</span>, <span class="param">handler</span>) → <span class="type">Application</span>
|
|
</div>
|
|
<div class="method-signature">
|
|
<span class="method-name">patch</span>(<span class="param">path</span>, <span class="param">handler</span>) → <span class="type">Application</span>
|
|
</div>
|
|
<p>Register route handlers. Handler receives <code>Request</code> and returns <code>Response</code>.</p>
|
|
<ul class="param-list">
|
|
<li><span class="param-name">path</span> <span class="param-type">(String)</span> - URL path with optional parameters (<code>:param</code>) or wildcards (<code>*</code>)</li>
|
|
<li><span class="param-name">handler</span> <span class="param-type">(Fn)</span> - Function receiving Request, returning Response</li>
|
|
</ul>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">addView</span>(<span class="param">path</span>, <span class="param">viewClass</span>) → <span class="type">Application</span>
|
|
</div>
|
|
<p>Registers a class-based view for all HTTP methods.</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">static_</span>(<span class="param">prefix</span>, <span class="param">directory</span>) → <span class="type">Application</span>
|
|
</div>
|
|
<p>Serves static files from a directory.</p>
|
|
<pre><code>app.static_("/assets", "./public")</code></pre>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">use</span>(<span class="param">middleware</span>) → <span class="type">Application</span>
|
|
</div>
|
|
<p>Adds middleware function. Middleware receives Request, returns Response or null to continue.</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">run</span>(<span class="param">host</span>, <span class="param">port</span>)
|
|
</div>
|
|
<p>Starts the server (blocking).</p>
|
|
|
|
<h2>Request Class</h2>
|
|
|
|
<div class="class-header">
|
|
<h3>Request</h3>
|
|
<p>Incoming HTTP request</p>
|
|
</div>
|
|
|
|
<h3>Properties</h3>
|
|
|
|
<table>
|
|
<tr>
|
|
<th>Property</th>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
<tr>
|
|
<td><code>method</code></td>
|
|
<td>String</td>
|
|
<td>HTTP method (GET, POST, etc.)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>path</code></td>
|
|
<td>String</td>
|
|
<td>Request path without query string</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>query</code></td>
|
|
<td>Map</td>
|
|
<td>Parsed query parameters</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>headers</code></td>
|
|
<td>Map</td>
|
|
<td>Request headers</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>body</code></td>
|
|
<td>String</td>
|
|
<td>Raw request body</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>params</code></td>
|
|
<td>Map</td>
|
|
<td>Route parameters from URL</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>cookies</code></td>
|
|
<td>Map</td>
|
|
<td>Parsed cookies</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>session</code></td>
|
|
<td>Session</td>
|
|
<td>Session data</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h3>Methods</h3>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">header</span>(<span class="param">name</span>) → <span class="type">String|null</span>
|
|
</div>
|
|
<p>Gets header value (case-insensitive).</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">json</span> → <span class="type">Map|List</span>
|
|
</div>
|
|
<p>Parses body as JSON (cached).</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">form</span> → <span class="type">Map</span>
|
|
</div>
|
|
<p>Parses body as form data (cached).</p>
|
|
|
|
<h2>Response Class</h2>
|
|
|
|
<div class="class-header">
|
|
<h3>Response</h3>
|
|
<p>HTTP response builder</p>
|
|
</div>
|
|
|
|
<h3>Static Factory Methods</h3>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">Response.text</span>(<span class="param">content</span>) → <span class="type">Response</span>
|
|
</div>
|
|
<p>Creates plain text response.</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">Response.html</span>(<span class="param">content</span>) → <span class="type">Response</span>
|
|
</div>
|
|
<p>Creates HTML response.</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">Response.json</span>(<span class="param">data</span>) → <span class="type">Response</span>
|
|
</div>
|
|
<p>Creates JSON response (automatically stringifies).</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">Response.redirect</span>(<span class="param">url</span>) → <span class="type">Response</span>
|
|
</div>
|
|
<div class="method-signature">
|
|
<span class="method-name">Response.redirect</span>(<span class="param">url</span>, <span class="param">status</span>) → <span class="type">Response</span>
|
|
</div>
|
|
<p>Creates redirect response (default 302).</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">Response.file</span>(<span class="param">path</span>) → <span class="type">Response</span>
|
|
</div>
|
|
<div class="method-signature">
|
|
<span class="method-name">Response.file</span>(<span class="param">path</span>, <span class="param">contentType</span>) → <span class="type">Response</span>
|
|
</div>
|
|
<p>Serves a file. Auto-detects content type if not specified.</p>
|
|
|
|
<h3>Instance Methods</h3>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">header</span>(<span class="param">name</span>, <span class="param">value</span>) → <span class="type">Response</span>
|
|
</div>
|
|
<p>Sets a response header.</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">cookie</span>(<span class="param">name</span>, <span class="param">value</span>) → <span class="type">Response</span>
|
|
</div>
|
|
<div class="method-signature">
|
|
<span class="method-name">cookie</span>(<span class="param">name</span>, <span class="param">value</span>, <span class="param">options</span>) → <span class="type">Response</span>
|
|
</div>
|
|
<p>Sets a cookie. Options: <code>path</code>, <code>maxAge</code>, <code>httpOnly</code>, <code>secure</code>.</p>
|
|
|
|
<h3>Properties</h3>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">status</span> → <span class="type">Num</span>
|
|
</div>
|
|
<p>Gets or sets HTTP status code.</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">body</span> → <span class="type">String</span>
|
|
</div>
|
|
<p>Gets or sets response body.</p>
|
|
|
|
<h2>View Class</h2>
|
|
|
|
<div class="class-header">
|
|
<h3>View</h3>
|
|
<p>Base class for class-based views</p>
|
|
</div>
|
|
|
|
<p>Subclass and override methods for each HTTP method:</p>
|
|
<pre><code>class UserView is View {
|
|
get(request) {
|
|
return Response.json({"users": []})
|
|
}
|
|
|
|
post(request) {
|
|
var data = request.json
|
|
return Response.json({"created": data})
|
|
}
|
|
}</code></pre>
|
|
|
|
<h2>Session Class</h2>
|
|
|
|
<div class="class-header">
|
|
<h3>Session</h3>
|
|
<p>Session data storage</p>
|
|
</div>
|
|
|
|
<h3>Properties and Methods</h3>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">id</span> → <span class="type">String</span>
|
|
</div>
|
|
<p>The session ID.</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">[key]</span> → <span class="type">any</span>
|
|
</div>
|
|
<p>Gets session value.</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">[key]=</span>(<span class="param">value</span>)
|
|
</div>
|
|
<p>Sets session value.</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">remove</span>(<span class="param">key</span>)
|
|
</div>
|
|
<p>Removes a session key.</p>
|
|
|
|
<h2>Client Class</h2>
|
|
|
|
<div class="class-header">
|
|
<h3>Client</h3>
|
|
<p>HTTP client for making requests</p>
|
|
</div>
|
|
|
|
<h3>Static Methods</h3>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">Client.get</span>(<span class="param">url</span>) → <span class="type">Map</span>
|
|
</div>
|
|
<div class="method-signature">
|
|
<span class="method-name">Client.get</span>(<span class="param">url</span>, <span class="param">options</span>) → <span class="type">Map</span>
|
|
</div>
|
|
<p>Makes GET request.</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">Client.post</span>(<span class="param">url</span>) → <span class="type">Map</span>
|
|
</div>
|
|
<div class="method-signature">
|
|
<span class="method-name">Client.post</span>(<span class="param">url</span>, <span class="param">options</span>) → <span class="type">Map</span>
|
|
</div>
|
|
<p>Makes POST request.</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">Client.put</span>(<span class="param">url</span>, <span class="param">options</span>) → <span class="type">Map</span>
|
|
</div>
|
|
<p>Makes PUT request.</p>
|
|
|
|
<div class="method-signature">
|
|
<span class="method-name">Client.delete</span>(<span class="param">url</span>, <span class="param">options</span>) → <span class="type">Map</span>
|
|
</div>
|
|
<p>Makes DELETE request.</p>
|
|
|
|
<h3>Client Options</h3>
|
|
|
|
<table>
|
|
<tr>
|
|
<th>Option</th>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
<tr>
|
|
<td><code>headers</code></td>
|
|
<td>Map</td>
|
|
<td>Request headers</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>body</code></td>
|
|
<td>String</td>
|
|
<td>Request body</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>json</code></td>
|
|
<td>Map/List</td>
|
|
<td>JSON body (auto-stringifies and sets Content-Type)</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h3>Response Format</h3>
|
|
<pre><code>{
|
|
"status": 200,
|
|
"headers": {"Content-Type": "application/json"},
|
|
"body": "{...}"
|
|
}</code></pre>
|
|
|
|
<h2>Examples</h2>
|
|
|
|
<h3>Basic Server</h3>
|
|
<pre><code>import "web" for Application, Response
|
|
|
|
var app = Application.new()
|
|
|
|
app.get("/", Fn.new { |req|
|
|
return Response.html("<h1>Hello World</h1>")
|
|
})
|
|
|
|
app.get("/api/users", Fn.new { |req|
|
|
return Response.json({"users": ["Alice", "Bob"]})
|
|
})
|
|
|
|
app.run("0.0.0.0", 8080)</code></pre>
|
|
|
|
<h3>Route Parameters</h3>
|
|
<pre><code>import "web" for Application, Response
|
|
|
|
var app = Application.new()
|
|
|
|
app.get("/users/:id", Fn.new { |req|
|
|
var userId = req.params["id"]
|
|
return Response.json({"id": userId})
|
|
})
|
|
|
|
app.get("/files/*", Fn.new { |req|
|
|
return Response.text("Wildcard route")
|
|
})
|
|
|
|
app.run("0.0.0.0", 8080)</code></pre>
|
|
|
|
<h3>Class-Based Views</h3>
|
|
<pre><code>import "web" for Application, Response, View
|
|
|
|
class ArticleView is View {
|
|
get(request) {
|
|
return Response.json({"articles": []})
|
|
}
|
|
|
|
post(request) {
|
|
var data = request.json
|
|
return Response.json({"created": data})
|
|
}
|
|
}
|
|
|
|
var app = Application.new()
|
|
app.addView("/articles", ArticleView)
|
|
app.run("0.0.0.0", 8080)</code></pre>
|
|
|
|
<h3>Sessions</h3>
|
|
<pre><code>import "web" for Application, Response
|
|
|
|
var app = Application.new()
|
|
|
|
app.get("/login", Fn.new { |req|
|
|
req.session["user"] = "Alice"
|
|
return Response.text("Logged in")
|
|
})
|
|
|
|
app.get("/profile", Fn.new { |req|
|
|
var user = req.session["user"]
|
|
if (user == null) {
|
|
return Response.redirect("/login")
|
|
}
|
|
return Response.text("Hello, %(user)")
|
|
})
|
|
|
|
app.run("0.0.0.0", 8080)</code></pre>
|
|
|
|
<h3>Middleware</h3>
|
|
<pre><code>import "web" for Application, Response
|
|
|
|
var app = Application.new()
|
|
|
|
app.use(Fn.new { |req|
|
|
System.print("%(req.method) %(req.path)")
|
|
return null
|
|
})
|
|
|
|
app.use(Fn.new { |req|
|
|
if (req.path.startsWith("/admin") && !req.session["isAdmin"]) {
|
|
return Response.redirect("/login")
|
|
}
|
|
return null
|
|
})
|
|
|
|
app.get("/", Fn.new { |req|
|
|
return Response.text("Home")
|
|
})
|
|
|
|
app.run("0.0.0.0", 8080)</code></pre>
|
|
|
|
<h3>HTTP Client</h3>
|
|
<pre><code>import "web" for Client
|
|
import "json" for Json
|
|
|
|
var response = Client.get("https://api.example.com/data")
|
|
System.print("Status: %(response["status"])")
|
|
System.print("Body: %(response["body"])")
|
|
|
|
var postResponse = Client.post("https://api.example.com/users", {
|
|
"json": {"name": "Alice", "email": "alice@example.com"}
|
|
})
|
|
|
|
var data = Json.parse(postResponse["body"])</code></pre>
|
|
|
|
<div class="admonition note">
|
|
<div class="admonition-title">Note</div>
|
|
<p>Sessions are stored in memory by default. Data is lost when the server restarts. For production, consider persisting session data to a database.</p>
|
|
</div>
|
|
</article>
|
|
|
|
<footer class="page-footer">
|
|
<a href="markdown.html" class="prev">markdown</a>
|
|
<a href="index.html" class="next">Overview</a>
|
|
</footer>
|
|
</main>
|
|
</div>
|
|
<script src="../js/main.js"></script>
|
|
</body>
|
|
</html>
|