2026-01-25 02:47:47 +01:00
<!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 >
2026-01-25 04:58:39 +01:00
< li >< a href = "string.html" > String</ a ></ li >
< li >< a href = "number.html" > Num</ a ></ li >
2026-01-25 02:47:47 +01:00
< li >< a href = "http.html" > http</ a ></ li >
< li >< a href = "websocket.html" > websocket</ a ></ li >
< li >< a href = "tls.html" > tls</ a ></ li >
< li >< a href = "net.html" > net</ a ></ li >
< li >< a href = "dns.html" > dns</ a ></ li >
< li >< a href = "json.html" > json</ a ></ li >
< li >< a href = "base64.html" > base64</ a ></ li >
< li >< a href = "regex.html" > regex</ a ></ li >
< li >< a href = "jinja.html" > jinja</ a ></ li >
< li >< a href = "crypto.html" > crypto</ a ></ li >
< li >< a href = "os.html" > os</ a ></ li >
< li >< a href = "env.html" > env</ a ></ li >
< li >< a href = "signal.html" > signal</ a ></ li >
< li >< a href = "subprocess.html" > subprocess</ a ></ li >
< li >< a href = "sqlite.html" > sqlite</ a ></ li >
< li >< a href = "datetime.html" > datetime</ a ></ li >
< li >< a href = "timer.html" > timer</ a ></ li >
< li >< a href = "io.html" > io</ a ></ li >
2026-01-25 04:58:39 +01:00
< li >< a href = "pathlib.html" > pathlib</ a ></ li >
2026-01-25 02:47:47 +01:00
< li >< a href = "scheduler.html" > scheduler</ a ></ li >
< li >< a href = "math.html" > math</ a ></ li >
< li >< a href = "uuid.html" > uuid</ a ></ li >
< li >< a href = "html.html" > html</ a ></ li >
< li >< a href = "argparse.html" > argparse</ a ></ li >
< li >< a href = "wdantic.html" > wdantic</ a ></ li >
< li >< a href = "dataset.html" > dataset</ a ></ li >
< li >< a href = "markdown.html" > markdown</ a ></ li >
< li >< a href = "web.html" class = "active" > web</ a ></ li >
</ ul >
</ div >
< div class = "section" >
< span class = "section-title" > Tutorials</ span >
< ul >
< li >< a href = "../tutorials/index.html" > Tutorial List</ 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 >
</ 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 >