Alpha. Vary is under active development and not ready for production use. Syntax, APIs, performance, and behaviour may change between releases.

HTTP Client

The http module provides a typed HTTP client with Result-based error handling, a fluent request builder, and a mock transport for deterministic testing.

import http

let resp = http.get("https://api.example.com/users").unwrap()
print(resp.status())    # 200
print(resp.body())      # raw response body

Basic requests

FunctionReturnsDescription
http.get(url)Result[HttpResponse, HttpError]Send a GET request
http.post(url, body)Result[HttpResponse, HttpError]Send a POST request
http.put(url, body)Result[HttpResponse, HttpError]Send a PUT request
http.del(url)Result[HttpResponse, HttpError]Send a DELETE request
http.patch(url, body)Result[HttpResponse, HttpError]Send a PATCH request
http.request(method, url)Result[HttpResponse, HttpError]Send with any method

All functions accept optional keyword arguments: headers (Dict), params (Dict), timeout_ms (Int, default 10000). post, put, and patch also accept body (Str).

HttpResponse

MethodReturnsDescription
.status()IntHTTP status code
.body()StrResponse body as text
.headers()Dict[Str, Str]Response headers
.header(name)Str?Single header value by name
.ok()BoolTrue if status code is 2xx
.url()StrThe request URL

JSON-first API

For JSON APIs, skip the intermediate HttpResponse and get a Result[Json, HttpError] directly:

import http

let data = http.get_json("https://api.example.com/items").unwrap()
let name = data.get_str("name")

let body = Json.empty_object().set_str("name", "alice")
let created = http.post_json("https://api.example.com/users", body).unwrap()
FunctionReturnsDescription
http.get_json(url)Result[Json, HttpError]GET and parse as JSON
http.post_json(url, payload)Result[Json, HttpError]POST JSON payload and parse response

Request builder

Use http.new(method, url) to construct requests with multiple headers or query parameters:

import http

let resp = http.new("GET", "https://api.example.com/search")
    .header("Authorization", "Bearer " + token)
    .query("q", "vary language")
    .query("limit", "10")
    .timeout(5000)
    .send()
    .unwrap()
MethodReturnsDescription
.header(name, value)HttpRequestBuilderAdd a request header
.body(text)HttpRequestBuilderSet the request body
.query(name, value)HttpRequestBuilderAdd a query parameter
.json(value)HttpRequestBuilderSet JSON request body
.timeout(ms)HttpRequestBuilderSet timeout in milliseconds
.send()Result[HttpResponse, HttpError]Execute the request

Mock transport for testing

Replace the global transport with a mock to test HTTP-dependent code without real network calls:

import http

let m = http.mock()
m.addRoute("GET https://api.example.com/ping", 200, "pong", {})
m.addRoute("POST https://api.example.com/users", 201, '{"id": 42}', {})

http.set_transport(m)

let resp = http.get("https://api.example.com/ping").unwrap()
print(resp.body())    # "pong"

http.clear_transport()    # restore real HTTP
FunctionReturnsDescription
http.mock()HttpMockTransportCreate a mock transport
http.set_transport(mock)NoneInstall mock as global transport
http.clear_transport()NoneRestore real HTTP transport
mock.addRoute(key, status, body, headers)NoneRegister a mock response (key is "METHOD url")
mock.call_count()IntNumber of requests made through the mock
mock.last_call()Str?Key of the most recent mock call
mock.all_calls()List[Str]All mock call keys in order
mock.reset()NoneClear all recorded calls

HttpError

MethodReturnsDescription
.kind()StrError category (see below)
.message()StrHuman-readable error detail

Error kinds:

KindWhen
"connection"Could not connect to the server
"timeout"Request exceeded the timeout
"protocol"Invalid HTTP response
"decode"Response body could not be decoded