Skip to content

HTTP client for REST and other web APIs. Responses come back as a table with status, body, headers and cookies; there is no response object to close. Things to know: HTTP error statuses (4xx, 5xx) are returned, not raised, so assert on response.status. Network failures and timeouts raise an error. Redirects are followed. Settings made with bearer(), basic(), timeout(), cookie() and the certificate functions stay active for the rest of the script run and apply to all later requests. TLS certificates are verified unless disableCertificateValidation() is called. Request bodies are text sent as UTF-8; encode tables with Json.encode first. Keep credentials in secrets: secret("name"). Headers can be given as a map, {["Content-Type"] = "application/json"}, which replaces a header of the same name, or as a list of "Name:value" strings, {"X-Trace:abc", "X-Trace:def"}, which adds a header and allows duplicates. List entries without a colon are ignored. In responses, header names are available in their original casing and in lower case, and a header that occurs more than once is a list of values.

  • Kind Library, a global in every script
  • Category APIs & Data
  • Functions 21

Example

Session login followed by an authenticated call

-- Log in, keep the session cookie, call an endpoint
Rest.timeout(15000)
local login = Rest.post(
"https://app.example.com/api/login",
{ ["Content-Type"] = "application/json" },
Json.encode({ user = "alice", password = secret("app_password") }))
Assert.equals(200, login.status)
local response = Rest.get("https://app.example.com/api/orders?status=open", { Accept = "application/json" })
Assert.equals(200, response.status)
print(response.headers["content-type"])
local orders = Json.decode(response.body)

Functions

  • get HttpResponse Sends a GET request and returns the response.
  • post HttpResponse Sends a POST request with a text body and returns the response.
  • put HttpResponse Sends a PUT request with a text body and returns the response.
  • patch HttpResponse Sends a PATCH request with a text body and returns the response.
  • delete HttpResponse Sends a DELETE request and returns the response.
  • multipart HttpResponse Sends a multipart/form-data POST request, for example a file upload.
  • download DownloadResponse Sends a GET request and saves the response body to a file in the project.
  • bearer self Sets a default "Authorization: Bearer TOKEN" header that is sent with every later request, to any host, until it is replaced by basic() or removed with clearAuth().
  • basic self Sets a default "Authorization: Basic BASE64(username:password)" header that is sent with every later request, to any host, until it is replaced by bearer() or removed with clearAuth().
  • clearAuth self Removes the default Authorization header set by bearer() or basic().
  • timeout self Sets the connect, response and connection-request timeouts to the same value, in milliseconds, for all later requests.
  • connectTimeout self Sets how long to wait while establishing the TCP/TLS connection, in milliseconds.
  • responseTimeout self Sets how long to wait for response data once connected, in milliseconds.
  • connectionRequestTimeout self Sets how long to wait for a connection from the client's connection pool, in milliseconds.
  • clearTimeouts self Removes the timeouts set by timeout() and its variants, restoring the defaults.
  • cookies RestCookie[] Returns the cookies currently in the cookie jar: those received through Set-Cookie headers and those added with cookie().
  • cookie self Adds a cookie to the cookie jar for the host of the given URL (the URL's path is ignored).
  • clearCookies self Empties the cookie jar, for example to start a new login session.
  • disableCertificateValidation self Turns off TLS certificate and host name verification for all later requests, to any host, for the rest of the run.
  • clientCertificate self Registers a PKCS#12 (.p12/.pfx) client certificate for mutual TLS.
  • cert self Alias for clientCertificate(host, port, file, passphrase).
Rest.get(url: string)→HttpResponseRest.get(url: string, headers: table)→HttpResponse

Sends a GET request and returns the response. Redirects are followed automatically. Any HTTP status, including 4xx and 5xx, comes back as a normal response; only network failures and timeouts raise an error ("Api request failed: ...").

Parameters

url string
The URL to request
headers table optional
Request headers, applied on top of the defaults set by bearer() and basic(). Either a map ({Accept = "application/json"}) or a list of "Name:value" strings; see the Rest library notes

Returns

HttpResponse The response of an HTTP request made with Rest.
Fields of HttpResponse
status number
HTTP status code, for example 200 or 404
body string
response body decoded as UTF-8 text, empty when the response has no body
response string
same value as body (older scripts use this name)
headers table
response headers by name. Each header is present under its original name and under its lower-case name (headers["content-type"]). The value is a string, or a list of strings when the header occurred more than once (such as Set-Cookie)
cookies RestCookie[]
all cookies in the Rest cookie jar after this response, not only those set by this response
All table shapes

Example

GET with a bearer token and an Accept header

Rest.bearer(secret("api_token"))
local response = Rest.get("https://api.example.com/users/1", { Accept = "application/json" })
Assert.equals(200, response.status)
local user = Json.decode(response.body)
print(user.name)
Rest.post(url: string, body: string)→HttpResponseRest.post(url: string, headers: table, body: string)→HttpResponse

Sends a POST request with a text body and returns the response. The body is sent as UTF-8 text and the Content-Type defaults to "text/plain; charset=UTF-8", so set the header yourself for JSON or form data. A table is not serialised: encode it first with Json.encode. Non-2xx statuses are returned, not raised.

Parameters

url string
The URL to post to
headers table
Request headers, applied on top of the defaults set by bearer() and basic()
body string
The request body, sent as UTF-8 text

Returns

HttpResponse The response of an HTTP request made with Rest.
Fields of HttpResponse
status number
HTTP status code, for example 200 or 404
body string
response body decoded as UTF-8 text, empty when the response has no body
response string
same value as body (older scripts use this name)
headers table
response headers by name. Each header is present under its original name and under its lower-case name (headers["content-type"]). The value is a string, or a list of strings when the header occurred more than once (such as Set-Cookie)
cookies RestCookie[]
all cookies in the Rest cookie jar after this response, not only those set by this response
All table shapes

Example

local response = Rest.post(
"https://api.example.com/orders",
{ ["Content-Type"] = "application/json", ["X-Request-Source"] = "reflex" },
Json.encode({ sku = "A-100", quantity = 2 }))
Assert.equals(201, response.status)
print(Json.decode(response.body).id)
Rest.put(url: string, body: string)→HttpResponseRest.put(url: string, headers: table, body: string)→HttpResponse

Sends a PUT request with a text body and returns the response. Body and Content-Type behave as in post().

Parameters

url string
The URL to send the request to
headers table
Request headers, applied on top of the defaults set by bearer() and basic()
body string
The request body, sent as UTF-8 text

Returns

HttpResponse The response of an HTTP request made with Rest.
Fields of HttpResponse
status number
HTTP status code, for example 200 or 404
body string
response body decoded as UTF-8 text, empty when the response has no body
response string
same value as body (older scripts use this name)
headers table
response headers by name. Each header is present under its original name and under its lower-case name (headers["content-type"]). The value is a string, or a list of strings when the header occurred more than once (such as Set-Cookie)
cookies RestCookie[]
all cookies in the Rest cookie jar after this response, not only those set by this response
All table shapes

Example

local response = Rest.put(
"https://api.example.com/users/1",
{ ["Content-Type"] = "application/json" },
Json.encode({ name = "Alice", active = true }))
Assert.equals(200, response.status)
Rest.patch(url: string, body: string)→HttpResponseRest.patch(url: string, headers: table, body: string)→HttpResponse

Sends a PATCH request with a text body and returns the response. Body and Content-Type behave as in post().

Parameters

url string
The URL to send the request to
headers table
Request headers, applied on top of the defaults set by bearer() and basic()
body string
The request body, sent as UTF-8 text

Returns

HttpResponse The response of an HTTP request made with Rest.
Fields of HttpResponse
status number
HTTP status code, for example 200 or 404
body string
response body decoded as UTF-8 text, empty when the response has no body
response string
same value as body (older scripts use this name)
headers table
response headers by name. Each header is present under its original name and under its lower-case name (headers["content-type"]). The value is a string, or a list of strings when the header occurred more than once (such as Set-Cookie)
cookies RestCookie[]
all cookies in the Rest cookie jar after this response, not only those set by this response
All table shapes

Example

local response = Rest.patch(
"https://api.example.com/users/1",
{ ["Content-Type"] = "application/merge-patch+json" },
'{"active": false}')
Assert.equals(200, response.status)
Rest.delete(url: string, body: string)→HttpResponseRest.delete(url: string, headers: table, body: string)→HttpResponse

Sends a DELETE request and returns the response. The body argument is required: pass "" when the request has no body. With two arguments the second one is always the body, so to send headers without a body call delete(url, headers, "").

Parameters

url string
The URL to send the request to
headers table
Request headers, applied on top of the defaults set by bearer() and basic()
body string
The request body; use "" for none

Returns

HttpResponse The response of an HTTP request made with Rest.
Fields of HttpResponse
status number
HTTP status code, for example 200 or 404
body string
response body decoded as UTF-8 text, empty when the response has no body
response string
same value as body (older scripts use this name)
headers table
response headers by name. Each header is present under its original name and under its lower-case name (headers["content-type"]). The value is a string, or a list of strings when the header occurred more than once (such as Set-Cookie)
cookies RestCookie[]
all cookies in the Rest cookie jar after this response, not only those set by this response
All table shapes

Example

local response = Rest.delete("https://api.example.com/users/1", { Accept = "application/json" }, "")
Assert.equals(204, response.status)
Rest.multipart(url: string, parts: table)→HttpResponseRest.multipart(url: string, headers: table, parts: table)→HttpResponse

Sends a multipart/form-data POST request, for example a file upload. The Content-Type header (including the boundary) is set automatically; do not set it yourself. Each entry of the parts table becomes one part: - name = "text": a text part sent as UTF-8 text/plain. - {name = "meta", value = "{}", contentType = "application/json"}: a text part with its own content type. - {name = "file", file = "docs/report.pdf", filename = "r.pdf", contentType = "application/pdf"}: a file part. "file" (alias "path") is a path in the project; it is fetched from the Reflex server when it is not in the workspace yet. "filename" defaults to the file's own name; "contentType" is guessed from the extension and falls back to application/octet-stream. Map entries take their part name from the key, list entries from their "name" field. The order of map entries is not guaranteed. Raises an error when the parts are not a table, a part has no name, neither "value" nor "file" is given, or a file does not exist.

Parameters

url string
The URL to post to
headers table
Request headers, applied on top of the defaults set by bearer() and basic()
parts table
The parts: {fieldName = "text"} entries and/or {name = ..., value or file = ..., filename = ..., contentType = ...} tables

Returns

HttpResponse The response of an HTTP request made with Rest.
Fields of HttpResponse
status number
HTTP status code, for example 200 or 404
body string
response body decoded as UTF-8 text, empty when the response has no body
response string
same value as body (older scripts use this name)
headers table
response headers by name. Each header is present under its original name and under its lower-case name (headers["content-type"]). The value is a string, or a list of strings when the header occurred more than once (such as Set-Cookie)
cookies RestCookie[]
all cookies in the Rest cookie jar after this response, not only those set by this response
All table shapes

Example

local response = Rest.multipart(
"https://api.example.com/documents",
{ Authorization = "Bearer " .. secret("api_token") },
{
description = "Quarterly report",
{ name = "file", file = "docs/report.pdf", contentType = "application/pdf" },
})
Assert.equals(201, response.status)
Rest.download(url: string, file: string)→DownloadResponseRest.download(url: string, headers: table, file: string)→DownloadResponse

Sends a GET request and saves the response body to a file in the project. Returns the response metadata plus the saved path and size; body and response are empty strings because the content is in the file. If the target ends with "/" or "\" or is an existing directory, the file name is taken from the Content-Disposition header, then from the last segment of the URL, then "download.bin". Otherwise the target is the file to write. Missing parent directories are created and an existing file is overwritten. The status is not checked: a 404 page is saved like any other body, so check status before using the file.

Parameters

url string
The URL of the file to download
headers table
Request headers, applied on top of the defaults set by bearer() and basic()
file string
Where to save it, relative to the project. A trailing "/" or an existing directory means "save inside this directory"; anything else is the file path to write

Returns

DownloadResponse The result of Rest.download: the response metadata, with the body saved to a file.
Fields of DownloadResponse
status number
HTTP status code, for example 200 or 404
file string
path of the saved file, relative to the project, with forward slashes
size number
size of the saved file in bytes
body string
always an empty string (the body is in the file)
response string
always an empty string (the body is in the file)
headers table
response headers by name. Each header is present under its original name and under its lower-case name. The value is a string, or a list of strings when the header occurred more than once
cookies RestCookie[]
all cookies in the Rest cookie jar after this response
All table shapes

Example

local response = Rest.download(
"https://example.com/exports/report.csv",
{ Authorization = "Bearer " .. secret("api_token") },
"downloads/")
Assert.equals(200, response.status)
print(response.file, response.size)
Rest.bearer(token: string)→self

Sets a default "Authorization: Bearer TOKEN" header that is sent with every later request, to any host, until it is replaced by basic() or removed with clearAuth(). A header with the same name in a request's own headers wins.

Parameters

token string
The token, without the "Bearer " prefix

Returns

self chainable The library itself, so calls can be chained.

Example

Rest.bearer(secret("api_token"))
local response = Rest.get("https://api.example.com/me")
Rest.basic(username: string, password: string)→self

Sets a default "Authorization: Basic BASE64(username:password)" header that is sent with every later request, to any host, until it is replaced by bearer() or removed with clearAuth(). A header with the same name in a request's own headers wins.

Parameters

username string
The user name
password string
The password

Returns

self chainable The library itself, so calls can be chained.

Example

Rest.basic(secret("api_user"), secret("api_password"))
local response = Rest.get("https://api.example.com/reports")
Rest.clearAuth()→self

Removes the default Authorization header set by bearer() or basic().

Returns

self chainable The library itself, so calls can be chained.
Rest.timeout(millis: number)→self

Sets the connect, response and connection-request timeouts to the same value, in milliseconds, for all later requests. The response timeout is the longest the client waits for data on the socket, not the total duration of the request. When a timeout expires the request raises an error. Without a call, connecting and leasing a connection time out after 3 minutes and a response may take forever. Use connectTimeout, responseTimeout or connectionRequestTimeout to set them separately. Raises an error when the value is smaller than 1.

Parameters

millis number
Timeout in milliseconds, at least 1

Returns

self chainable The library itself, so calls can be chained.

Example

Rest.timeout(10000)
local response = Rest.get("https://api.example.com/slow-report")
Rest.connectTimeout(millis: number)→self

Sets how long to wait while establishing the TCP/TLS connection, in milliseconds. Default: 3 minutes. Raises an error when the value is smaller than 1.

Parameters

millis number
Connect timeout in milliseconds, at least 1

Returns

self chainable The library itself, so calls can be chained.
Rest.responseTimeout(millis: number)→self

Sets how long to wait for response data once connected, in milliseconds. It applies to each wait for data, not to the whole transfer. Default: no limit. Raises an error when the value is smaller than 1.

Parameters

millis number
Response timeout in milliseconds, at least 1

Returns

self chainable The library itself, so calls can be chained.

Example

Rest.responseTimeout(30000)
Rest.connectionRequestTimeout(millis: number)→self

Sets how long to wait for a connection from the client's connection pool, in milliseconds. Every request builds its own client, so this rarely matters. Default: 3 minutes. Raises an error when the value is smaller than 1.

Parameters

millis number
Connection-request timeout in milliseconds, at least 1

Returns

self chainable The library itself, so calls can be chained.
Rest.clearTimeouts()→self

Removes the timeouts set by timeout() and its variants, restoring the defaults.

Returns

self chainable The library itself, so calls can be chained.
Rest.cookies()→RestCookie[]

Returns the cookies currently in the cookie jar: those received through Set-Cookie headers and those added with cookie(). The jar lives as long as the Rest library (one script run) and is sent automatically with later requests to matching hosts.

Returns

RestCookie[] A cookie stored in the Rest session.
Fields of RestCookie
name string
cookie name
value string
cookie value
domain string
domain the cookie applies to
path string
path the cookie applies to
secure boolean
only sent over HTTPS
httpOnly boolean
not readable by page scripts
persistent boolean
the cookie has an expiry date
expiry string
expiry date in ISO 8601, nil for session cookies
All table shapes

Example

Rest.post(
"https://app.example.com/login",
{ ["Content-Type"] = "application/x-www-form-urlencoded" },
"user=alice&password=" .. secret("app_password"))
for _, c in ipairs(Rest.cookies()) do
print(c.name, c.domain, c.secure)
end
Rest.cookie(url: string, name: string, value: string)→selfRest.cookie(url: string, name: string, value: string, path: string)→self

Adds a cookie to the cookie jar for the host of the given URL (the URL's path is ignored). The cookie is marked secure when the URL uses https. Raises an error when the URL has no host.

Parameters

url string
A URL on the host that should receive the cookie
name string
Cookie name
value string
Cookie value
path string optional
Path the cookie applies to; "/" when left out

Returns

self chainable The library itself, so calls can be chained.

Example

Rest.cookie("https://app.example.com", "session", secret("session_id"))
local response = Rest.get("https://app.example.com/dashboard")
Rest.clearCookies()→self

Empties the cookie jar, for example to start a new login session.

Returns

self chainable The library itself, so calls can be chained.
Rest.disableCertificateValidation()→self

Turns off TLS certificate and host name verification for all later requests, to any host, for the rest of the run. Meant for test environments with self-signed certificates; it cannot be switched back on. Leave it out when the server has a valid certificate.

Returns

self chainable The library itself, so calls can be chained.

Example

Rest.disableCertificateValidation()
local response = Rest.get("https://test.internal.example:8443/health")
Rest.clientCertificate(host: string, port: number, file: string, passphrase: string)→self

Registers a PKCS#12 (.p12/.pfx) client certificate for mutual TLS. It is presented only on requests to the given host and port (a URL without a port means 443 for https and 80 for http); calling it again for the same host and port replaces the certificate. The file is read from the project (fetched from the Reflex server when it is not in the workspace). A copy fetched from the server is removed from the workspace after loading; a file that was already in the workspace is left alone. Raises "Failed to configure client certificate: ..." when the port is outside 1-65535, the file is missing, or the passphrase is wrong. Use secret() for the passphrase.

Parameters

host string
Host name of the HTTPS endpoint, without scheme or port
port number
Port of the endpoint, 1-65535
file string
PKCS#12 file in the project
passphrase string
Passphrase of the file; nil is treated as an empty one

Returns

self chainable The library itself, so calls can be chained.

Example

Rest.clientCertificate("api.partner.example", 443, "certs/client.p12", secret("client_cert_passphrase"))
local response = Rest.get("https://api.partner.example/orders")
Rest.cert(host: string, port: number, file: string, passphrase: string)→self

Alias for clientCertificate(host, port, file, passphrase).

Parameters

host string
Host name of the HTTPS endpoint, without scheme or port
port number
Port of the endpoint, 1-65535
file string
PKCS#12 file in the project
passphrase string
Passphrase of the file; nil is treated as an empty one

Returns

self chainable The library itself, so calls can be chained.