Builtin Library
README.md
http Module
Public Luau surface over the __http Internal FFI namespace — async
HTTP GET / POST returning JSON or raw bytes.
Purpose
Wrap the raw __http.* FFI namespace in a typed Luau table that gets
auto-injected as _G.http via the prelude. Every method returns a
promise handle: pass it to task.await(handle) to block the
coroutine until the request completes.
Usage
-- GET JSON
local data = task.await(http.get_json("https://api.example.com/info"))
-- POST JSON
local resp = task.await(http.post_json(
"https://api.example.com/users",
{ Authorization = "Bearer " .. token },
{ name = "Alice", age = 42 }
))
-- Download a binary asset
local bytes = task.await(http.get_bytes("https://example.com/sound.ogg"))
vfs.write("/zero/source/audio/sound.ogg", bytes)
The bound a request carries
Every method takes a deadline after its own arguments: how long the request is given to be answered, in milliseconds. Left out, the engine's own bound applies, which is what settles a call against a peer that accepts the connection and answers nothing. Passed as 0, no bound applies, which a transfer whose length the caller knows better than the engine does names.
A request given up on resolves like any other failure, with the engine's error
envelope: { "__http_error": true, "error": "Network error: no answer within <n>ms" }.
-- Give this call three seconds to be answered
local credential = task.await(http.post_json(tokenUrl, headers, nil, 3000))
-- A download whose length the caller knows better than the engine does
local bytes = task.await(http.get_bytes(assetUrl, nil, 0))
Statuses the caller expects
Every method takes, as its last argument, the HTTP statuses the caller handles as an answer it expected: the 404 of a read whose subject may not exist yet, say. A response with one of them settles the future exactly as any other non-2xx does, with the error envelope, and the engine logs it as information. Every other failure, a status the caller did not name and a request that reached no status at all, is logged as an error. So an error line in the log is always a failure somebody has to look at. Each entry is a whole number from 100 to 999, and a call naming anything else raises, naming the entry.
-- A world that has published nothing answers 404: an outcome, not a failure
local answer = task.await(http.get_json(manifestUrl, headers, nil, { 404 }))
Exports
http.get_json(url, headers?, timeoutMs?, expectedStatuses?) -> promiseIdhttp.get_bytes(url, headers?, timeoutMs?, expectedStatuses?) -> promiseIdhttp.post_json(url, headers?, body?, timeoutMs?, expectedStatuses?) -> promiseIdhttp.post_bytes(url, headers?, body?, timeoutMs?, expectedStatuses?) -> promiseIdhttp.request(method, url, headers?, body?, timeoutMs?, expectedStatuses?) -> promiseIdhttp.request_raw(method, url, headers?, body?, timeoutMs?, expectedStatuses?) -> promiseId