Skip to content
Kavachकवच

HTTP: JSON over HTTP

● Intermediate3 min

post_json and get_json send and read your own types; read_json and json_response do it on the server. The type is the contract.

use std.http
use std.json
use std.net

type Order {
    id: Int
    item: String
}

fn orders(r: Request) -> Response {
    const wanted = http.read_json<Order>(r) catch _ => return http.text(400, "not an order")
    http.json_response(200, json.of(Order(id: wanted.id, item: "{wanted.item}, packed")))
}

fn main() ! Error {
    const listener = try net.listen("127.0.0.1:0")
    const _server = spawn http.serve(listener, orders)
    const url = "http://{listener.address()}/orders"
    const packed = try http.post_json<Order>(url, json.of(Order(id: 7, item: "pen")))
    print(packed.item)
}

The program ran and printed:

kavach run json.kav

pen, packed
json.kav: Kavach code, then what running it prints

The client and the server share Order. A body that isn't an Order is refused with status 400 on the server, and with BadJson on the client. A status that isn't a success fails with Status(code):

use std.http
use std.net

type Order {
    id: Int
}

fn shop(r: Request) -> Response {
    if r.path == "/orders/7" {
        return http.text(200, "\{\"id\": 7}")
    }
    http.text(404, "no such order")
}

fn main() ! Error {
    const listener = try net.listen("127.0.0.1:0")
    const _server = spawn http.serve(listener, shop)
    const base = "http://{listener.address()}"
    const found = try http.get_json<Order>("{base}/orders/7")
    print("found {found.id}")
    const missing = http.get_json<Order>("{base}/orders/8") catch e => {
        print("failed: {e}")
        return
    }
    print(missing.id)
}

The program ran and printed:

kavach run status.kav

found 7failed: Status(code: 404)
status.kav: Kavach code, then what running it prints