Skip to content
Kavachकवच

HTTP: Calling an API

● Intermediate3 min

http.get and http.post call a URL and give its Response: the status, the headers and the body.

const page = try http.get("https://example.com/")
print(page.status)
print(page.body.text() ?? "")
syntax: Kavach code

When a call can't work, the error says why. A refused connection and an address that isn't HTTP:

use std.http
use std.net

fn main() {
    for url in ["http://127.0.0.1:1/", "ftp://example.com/file"] {
        const page = http.get(url) catch e => match e {
            HttpError.BadUrl(u) => {
                print("not an http address: {u}")
                return
            }
            HttpError.Network(cause) => {
                print("couldn't connect: {cause}")
                continue
            }
            _ => {
                print("failed: {e}")
                continue
            }
        }
        print(page.status)
    }
}

The program ran and printed:

kavach run errors.kav

couldn't connect: Refused(address: "127.0.0.1:1")not an http address: ftp://example.com/file
errors.kav: Kavach code, then what running it prints
  • Network(…): the connection failed, with the NetError inside.
  • BadUrl: not an http:// or https:// address.
  • Status(code): the server answered, but not with success (from the JSON helpers).
  • BadMessage, BadJson: the answer was broken, or not the JSON you asked for.

Every network wait has a time limit, so a server that stops answering can't hang your program: see Timeouts.

Any method, any headers

http.request(method, url, headers:, body:) sends any method with the headers you give: a PUT or DELETE, a bearer token, basic auth, if-none-match:

use std.http
use std.net

fn echo(r: Request) -> Response {
    const auth = r.header("authorization") ?? "none"
    http.text(200, "{r.method} {r.path}, auth: {auth}, body: {r.body.text() ?? ""}")
}

fn main() ! Error {
    const listener = try net.listen("127.0.0.1:0")
    const _server = spawn http.serve(listener, echo)
    const url = "http://{listener.address()}/orders/7"
    const token = Header(name: "authorization", value: "Bearer test-token")
    const put = try http.request("PUT", url, headers: [token], body: "paid".bytes())
    print(put.body.text() ?? "")
    const gone = try http.request("DELETE", url)
    print(gone.body.text() ?? "")
}

The program ran and printed:

kavach run request.kav

PUT /orders/7, auth: Bearer test-token, body: paidDELETE /orders/7, auth: none, body:
request.kav: Kavach code, then what running it prints
  • host, content-length and connection are the client's own, so ones you give are left out.
  • It uses HTTP/2 when the server offers it with TLS, and HTTP/1.1 otherwise.
  • On a session, s.request(method, path, …) does the same on its connection.
tested