Skip to content

HTTP

The http namespace provides an HTTP/HTTPS client and server. HTTPS requires OpenSSL.

let res = http.get("http://example.com/api")
print(res.status) // 200
print(res.body) // response body string
print(res.headers) // map of lowercase header names
// Simple string body
let res = http.post("http://example.com/api", "hello")
// With headers
let res = http.post("http://example.com/api", {
body: "{\"name\": \"Ada\"}",
headers: {"Content-Type": "application/json"}
})
let res = http.request({
method: "PUT",
url: "http://example.com/api/1",
body: "updated data",
headers: {"Content-Type": "text/plain"}
})

All client methods return:

{
status: 200,
body: "...",
headers: {"content-type": "text/html", ...}
}

Header names are lowercased for consistent access.

Pass a handler function to http.createServer. The handler receives a request map and returns a response map:

let server = http.createServer(lam{ req in
if (req.path == "/") {
return {
status: 200,
body: "<h1>Hello!</h1>",
headers: {"Content-Type": "text/html"}
}
}
return {status: 404, body: "Not Found"}
})
server.listen(8080)
FieldDescription
method"GET", "POST", etc.
pathURL path (e.g. "/hello")
queryParsed query parameters as a map
headersMap of lowercase header names
bodyRequest body string
FieldDefaultDescription
status200HTTP status code
body""Response body
headers{"Content-Type": "text/plain"}Response headers

You can also return a plain string, which becomes a 200 text/plain response.

HelperDescription
http.json(obj, status?)JSON response with application/json
http.text(str, status?)Plain text response
http.html(str, status?)HTML response with charset=utf-8
http.redirect(url, status?)Redirect (302 by default)
http.file(path, status?)Serve a file with auto-detected MIME type
return http.json(data)
return http.json({error: "not found"}, 404)
return http.text("hello")
return http.html("<h1>Hi</h1>")
return http.redirect("/login")
return http.redirect("/new-url", 301)
return http.file("public/style.css")

http.sse(req, callback) keeps the connection open for real-time streaming:

server.get("/events", lam{ req, params in
return http.sse(req, lam{ send in
for (i in 0..10) {
send(json.stringify({count: i}), "update")
time.sleep(1000)
}
send("done", "close")
})
})

If the handler throws an error, the server returns a 500 response and continues running.

The server handles SIGINT (Ctrl-C) and SIGTERM gracefully. Code after listen() runs after shutdown:

server.listen(8080)
print("Shutting down...")
db.close()
FunctionDescription
http.encodeURI(str)Percent-encode a string (RFC 3986)
http.decodeURI(str)Decode percent-encoded sequences
http.encodeURI("hello world") // "hello%20world"
http.decodeURI("hello%20world") // "hello world"
let u = url.parse("https://example.com:8080/api?key=val")
print(u.scheme) // "https"
print(u.host) // "example.com"
print(u.port) // 8080
print(u.path) // "/api"
print(u.query) // "key=val"

For Express-style routing with path parameters, see the router grain.

use "router"
let server = router.create()
server.get("/users/:id", lam{ req, params in
return {status: 200, body: "User %{params.id}"}
})
server.listen(8080)