Skip to content

Async Sockets

ZZ I/O is non-blocking by default. This guide covers the two network surfaces: HTTP for web traffic and TCP sockets for everything else.

Client calls return Result<Response, str> — handle both arms:

import std.http
match http.get("https://api.example.com/users/1", {}) {
.ok(res) => {
println(http.status(res))
println(http.text(res))
},
.err(e) => println("request failed: {e}"),
}

Post JSON with explicit headers:

import std.http
import std.json
payload := json.stringify({"name": "Ada"})
headers := {"content-type": "application/json"}
match http.post("https://api.example.com/users", payload, headers) {
.ok(res) => println("created: {http.status(res)}"),
.err(e) => println("request failed: {e}"),
}

Build a route table with pipelines, then listen. Handlers take the request and return the response body:

import std.http
server := http.server()
|> http.get(_, "/", |body: str| "Hello, World!")
|> http.post(_, "/echo", |body: str| body)
http.listen(server, 8080)

Prove routes with http.handle before ever opening a port:

response := http.handle(server, "GET", "/", "")
println(response) // Hello, World!

Drop to std.net when the protocol isn’t HTTP. Every call returns a Result:

import std.net
match net.tcp_connect("example.com:80", 5000) {
.ok(stream) => {
net.tcp_write(stream, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
match net.tcp_readline(stream) {
.ok(line) => println("status: {line}"),
.err(e) => println("read failed: {e}"),
}
net.tcp_close(stream)
},
.err(e) => println("connect failed: {e}"),
}

Serve with tcp_listen + tcp_accept in a loop, and set deadlines with set_read_timeout / set_write_timeout so slow peers can’t hang you.