Chapter 17: Web Development
Build web applications entirely in Wyn - HTTP server, routing, templates, database, and deployment.
Quick Start
bash
wyn init myapp --web
cd myapp
wyn run
# Server running at http://localhost:8080HTTP Server
wyn
fn handle(method: string, path: string, body: string, fd: int) {
if path == "/" {
Http.respond(fd, 200, "<h1>Hello!</h1>")
return
}
if path == "/api/data" {
Http.respond_json(fd, 200, "{\"status\": \"ok\"}")
return
}
Http.respond(fd, 404, "Not Found")
}
fn main() -> int {
var server = Http.listen(8080)
while true {
var req = Http.accept(server)
if req > 0 {
spawn handle_request(req)
}
}
return 0
}
fn handle_request(req: int) -> int {
handle(Http.method(req), Http.path(req), Http.body(req), req)
Http.close_client(req)
System.gc()
return 0
}Each request is handled in its own spawned task - concurrent by default.
Templates
Create templates/page.html:
html
<h1>${title}</h1>
${if:logged_in}
<p>Welcome, ${username}!</p>
<ul>
${each:items}<li>${item}</li>
${endeach}</ul>
${else}
<p>Please log in</p>
${endif}Render from Wyn:
wyn
var ctx = { "title": "My App", "logged_in": "true", "username": "Alice" }
ctx.insert("items", "Home,About,Contact")
var html = Template.render("templates/page.html", ctx)
Http.respond(fd, 200, html)Values are HTML-escaped by default. Use ${raw:key} for trusted HTML.
Database
wyn
var db = Db.open("app.db")
Db.exec(db, "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
// Always use parameterized queries - prevents SQL injection
Db.exec_p(db, "INSERT INTO users (name, email) VALUES (?, ?)", ["Alice", "[email protected]"])
var users = Db.query_p(db, "SELECT name FROM users WHERE name LIKE ?", ["%ali%"])Environment Config
wyn
System.load_env(".env")
var port = System.env("PORT")
var db_path = System.env("DATABASE_URL")Deployment
Add to wyn.toml:
toml
[deploy.prod]
host = "myserver.com"
user = "deploy"
key = "~/.ssh/id_ed25519"
path = "/opt/myapp"
os = "linux"
pre = "systemctl stop myapp"
post = "systemctl start myapp"Deploy:
bash
wyn deploy prodOne command: cross-compiles for Linux, uploads binary, restarts service. Your entire app is a single binary with no dependencies.
Exercises
- Build a URL shortener with SQLite storage
- Add a JSON API that returns a list of items
- Create a template-based blog with multiple pages
Previous: Chapter 16: Python Libraries | Next: Chapter 18: Toolchain