request module
Axios-style HTTP client. Every verb returns a Future — pair with wait for straight-line code. An optional config map per call carries headers/params/timeout/etc. JSON and form bodies auto-encode. Connection pooling, before/after interceptors, file upload/download.
import "request" as r;
function main() {
var resp = wait r.get("https://api.example.com/users/1");
print(resp.status, resp.body);
var created = wait r.post(
"https://api.example.com/users",
{ name: "Alice" }, // auto-JSON
{ headers: { "X-Trace": "abc" }, timeout: 5000 }
);
print("created id:", created.data.id);
}
main().fail(function (e) { print("err:", e); });
Verb shortcuts
Every verb accepts an optional config map for headers, params (query), timeout, etc. The verb's URL, method, and body always win over config — config is purely additive.
| Function | Description |
|---|---|
r.get(url, config?) | Returns Future<resp>. |
r.head(url, config?) | |
r.delete(url, config?) | |
r.post(url, data, config?) | data can be a string (raw body) or a map (auto-JSON). |
r.put(url, data, config?) | |
r.patch(url, data, config?) | |
r.post_form(url, fields, config?) | URL-encoded form body. |
r.request(config) | Full-options form: {url, method, headers, body, json, form, params, timeout, ...}. |
Config keys
| Key | Description |
|---|---|
headers | Map of header name → value. Merged with instance defaults. |
params | Map serialized as query string and appended to the URL. |
timeout | Milliseconds. Rejected with a timeout error if exceeded. |
json | Map sent as JSON body (sets Content-Type: application/json). |
form | Map sent as application/x-www-form-urlencoded. |
body | Raw string body. You set Content-Type yourself. |
data | Smart: map → JSON, string → text/plain. |
pool | true to use keep-alive pool for this request. |
tls | TLS options (e.g. { verify: false } for self-signed). |
base_url | (instance only) prepended to relative URLs. |
Instances
var api = r.create({
base_url: "https://api.example.com",
headers: { "Authorization": "Bearer " + token }
});
var users = wait api.get("/users", { params: { limit: 10 } });
| Function | Description |
|---|---|
r.create(defaults) → instance | Bind a base URL, default headers/timeout/etc. Instance has the same verb shape as the module. |
r.before(fn) / api.before(fn) | Hook before(cfg) → cfg — modify config before send. |
r.after(fn) / api.after(fn) | Hook after(resp) → resp — modify response before return. |
File transfer
| Function | Description |
|---|---|
r.download(url, dest, config?) → Future | Stream url to file dest. Resolves with {status, headers, dest, bytes_written, ok}. |
r.upload(url, file, config?) → Future | POST file as multipart. file is a path string or a spec map {path, name, filename, content_type}. Extra fields via config.fields. |
var dl = wait r.download("https://example.com/big.zip", "./big.zip");
print("downloaded", dl.bytes_written, "bytes to", dl.dest);
var up = wait r.upload(
"https://example.com/upload",
{ path: "./report.pdf", name: "report", content_type: "application/pdf" },
{ fields: { user: "alice" }, headers: { "X-Trace": "abc" } }
);
Connection pool
request keeps a keep-alive pool per scheme://host:port. Enable per-request via config.pool: true or default via r.create({...pool: true}). Call r.shutdown() at process end to drain it cleanly.
Response object
resp exposes:
status— HTTP status code.headers— map with lowercased keys.body— raw response body string.data— parsed body when content-type is JSON; otherwise same asbody.ok—trueifstatusis 2xx.json()— re-parsebodyas JSON on demand.
A 4xx/5xx response fulfills the Future (you get a resp with ok=false). The Future only rejects on transport-level errors (DNS, TCP, TLS, timeout, malformed response).
try {
var resp = wait r.get(url, { timeout: 3000 });
if (resp.ok) { print("got:", resp.body); }
else { print("server said:", resp.status); }
} catch (e) {
print("transport error:", e);
}