HTTP
Also known as: web server client rest api request response endpoint route fetch curl express flask status code
● Intermediate6 minBefore this: JSON, TasksSpec 14.11
std.http calls web APIs and serves them: HTTP/1.1 and HTTP/2, with HTTP/3 for calls, written in Kavach itself.
use std.http
use std.net
fn hello(r: Request) -> Response {
http.text(200, "hello from {r.path}")
}
fn main() ! Error {
const listener = try net.listen("127.0.0.1:0")
const _server = spawn http.serve(listener, hello)
const page = try http.get("http://{listener.address()}/home")
print(page.status)
print(page.body.text() ?? "")
}The program ran and printed:
kavach run server.kav
200hello from /home
hellois the handler: it takes aRequestand gives aResponse.net.listen("127.0.0.1:0")lets the system pick a free port;listener.address()says which.spawn http.serve(…)serves in a task of its own, and stops whenmainreturns: a server can't be left running by mistake.http.getcalls it, here from the same program; a real client is any other program, in any language.
Every core at work
http.serve runs each connection in a task of its own, spawned with spawn cores, so in a release build (kavach build) handlers run at once on every core. kavach run answers them on one core, in turn, with the same responses.
- A handler that computes answered in 2.5–3.0 s instead of 18–20 s on one core.
- A handler that does nearly nothing answered in 131–221 ms instead of 461–633 ms on one core.
- Measured on Windows (24 cores, 32 clients making 200 requests each on kept-open connections).
- Handlers share nothing but what they reach through a
Sharedvalue or a channel. Each handler's printed lines come out in its own order, whole.
Every function
| Function | Gives |
|---|---|
http.get(url) -> Response ! HttpError | GET url |
http.post(url, body) -> Response ! HttpError | POST url with body (Bytes) |
http.request(method, url, headers: [Header] = [], body: Bytes = Bytes([])) -> Response ! HttpError | Any method, with the headers given and a body: a form post with basic auth, a bearer token, PUT, PATCH, DELETE, if-none-match. HTTP/2 when the server offers it with TLS, else HTTP/1.1; host, content-length and connection are the client's own, so ones given are left out |
http.get3(url) -> Response ! HttpError | GET url over HTTP/3 |
http.open(url) -> Session ! HttpError | A session: one HTTP/1.1 connection to the server of url (http:// or https://; the path is not used), kept open for several requests |
s.get(path), s.post(path, body) -> Response ! HttpError | A request on session s's connection, waiting for its response |
s.request(method, path, headers: [Header] = [], body: Bytes = Bytes([])) -> Response ! HttpError | The same as http.request, on session s's connection |
s.close() | Closes the session's connection |
http.serve(listener, handler, limits: ServeLimits()) ! NetError | Serves HTTP on listener: each connection in a task of its own, on any core (spawn cores, 9.8), its requests answered by handler: fn(Request) -> Response, each client held to limits (below). It runs until the function that called it returns, which cancels it (9.2) |
http.text(status, body) -> Response | A response with text |
http.get_json<T>(url) -> T ! HttpError | GET url, the response's JSON body decoded into a T (json.decode<T>, 2.12) |
http.post_json<T>(url, body) -> T ! HttpError | POST url with the Json value body, the response's JSON decoded into a T |
http.json_response(status, value) -> Response | A response with the Json value value (write json.of(order) for a typed value) |
http.read_json<T>(request) -> T ! JsonError | A request's JSON body decoded into a T |
Network access needs the Net capability, so a pub function that calls an API says uses Net, and an agent must list it in its can: see Capabilities.
One page for each form
Go deeper the why, for readers who want it
HTTP is written in Kavach, on top of std.net: HTTP/1.1, HTTP/2 with its header compression, and HTTP/3 over QUIC. https:// addresses go through TLS, offering HTTP/2 first. Programs that speak HTTP/2 or 3 themselves, as gRPC does, use the parts in std.http.h2 and std.http.h3.
Check yourself
spawn http.serve(…) when the function that started it returns?