Skip to content

wynlang/web

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

web

Batteries-included HTTP for Wyn. A thin, obvious layer over the native Http builtins: request parsing, JSON/HTML/text responses, safe static files, and HTML page building. Concurrency is the language's: spawn one handler per request and every handler runs on the coroutine scheduler.

Install

wyn pkg add web        # resolves to github.com/wynlang/web

A complete server

import web

fn handle(conn: int) {
    // one coroutine per connection — serves keep-alive requests in a loop
    while true {
        var req = web.read_request(conn)
        if req.len() == 0 { return }
        route(req)
    }
}

fn route(req: string) {
    if web.is(req, "GET", "/") == 1 {
        web.html(req, 200, web.page("Hello", "<h1>Hello from Wyn</h1>", ""))
    } else if web.is(req, "GET", "/api/greet") == 1 {
        var name = web.param(req, "name")
        if name.len() == 0 { name = "world" }
        var out = "{\"greeting\":\"hello, "
        out = out + web.json_escape(name)
        out = out + "\"}"
        web.json(req, 200, out)
    } else if web.is_under(req, "GET", "/static/") == 1 {
        web.serve_static(req, "/static/", "public")
    } else {
        web.not_found(req)
    }
}

fn main() {
    var server = web.listen(8080)
    println("http://localhost:8080")
    while true {
        var conn = web.accept(server)
        if conn > 0 { spawn handle(conn) }
    }
}

API

Serverlisten(port) -> int, accept(server) -> int (blocks; returns the connection fd to pass to your spawned handler), read_request(conn) -> string (inside the handler; parks cooperatively — a slow client never stalls others).

Measured on the hello example (ab, macOS arm64): 22,000+ req/s with keep-alive, zero failed requests at 200 concurrent connections (~7,200 req/s connection-per-request).

Requestmethod(req), path(req) (query stripped), query(req), param(req, name), body(req), fd(req), is(req, method, path), is_under(req, method, prefix).

Responseshtml/json/text(req, status, content), not_found(req), method_not_allowed(req), bad_request(req, message) (message JSON-escaped), redirect(req, location).

Static filesserve_static(req, prefix, dir): traversal-safe (.. rejected), MIME from extension via mime_type(path), index.html default.

Building outputpage(title, body_html, extra_head) (complete styled HTML5 page; title escaped), escape(s) (HTML), json_escape(s).

Test

wyn test

Notes

The request is the runtime's packed METHOD|PATH|BODY|FD string; accessors parse what they need. When cross-module struct support lands in the compiler, this grows a real Request type without breaking the function surface.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors