Skip to content

Client

HTTP client for making web requests.

Constructor

Client ... func?

Warning

unix_socket is not container-transparent. It connects to a Unix socket on the host where the Do process is running, not through the shell agent's container filesystem/network translation layer.

Parameters

Name Type Description
unix_socket Str Path to a Unix domain socket to connect through (Unix only)
proxy Str|url.Url|nil Proxy URL for all requests, or nil to disable system proxy
cookies Bool Enable a per-client cookie jar for session-style workflows
ca_cert Str|Bin PEM-encoded CA certificate to add to the trust store
identity Str|Bin PKCS#12/PFX client certificate for mutual TLS
password Str Password for the PKCS#12 identity (defaults to empty)
invalid_certs :DANGER_ACCEPT: Pass :DANGER_ACCEPT: to disable TLS certificate validation
func func Callable to run with the client; auto-closes when done

Returns

Client when no func is provided, otherwise the result of calling func

let client = Client()

Proxy

By default, the client respects system proxy environment variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY). Pass proxy: to set an explicit proxy or proxy: nil to disable proxy detection entirely.

# Explicit proxy
let client = Client proxy: "http://proxy.corp:8080"

# Disable system proxy
let client = Client proxy: nil

Cookies

Pass cookies: true to enable automatic storage and replay of cookies on that client instance. Cookie state is isolated per client and is not shared with the top-level http.get / http.post helpers.

let client = Client cookies: true

client.post https://example.com/login
client.get https://example.com/dashboard do |resp|
  echo $resp.status

TLS Certificates

Use ca_cert: to trust an additional CA certificate (PEM format), and identity: with password: for client certificate authentication (PKCS#12/PFX format).

# Custom CA certificate
let client = Client ca_cert: (fs.read /path/to/ca.pem)

# Client certificate authentication
let client = Client
  identity: (fs.read /path/to/client.pfx)
  password: secret

Disabling Certificate Validation

Pass invalid_certs: :DANGER_ACCEPT: to disable TLS certificate validation. This is dangerous and should only be used for testing.

let client = Client invalid_certs: :DANGER_ACCEPT:

Methods

get | post | ...

get url :headers? :query? :status? block?
head ...
delete ...
options ...
trace ...
connect ...

post url :headers? :body? :json? :lines? :multipart? :query? :status? block?
put ...
patch ...

Makes an HTTP request using the specified verb.

Parameters

Name Type Description
url Str The URL to request
body Str|Bin|input Request body; accepts iterables for streaming
json any Request body as JSON value (auto-serialized)
lines input Stream request body with newlines between elements
multipart input Multipart/form-data parts
headers Dict Dictionary of headers; repeated keys are accepted
query Dict Dictionary of query parameters; repeated keys are accepted
status :IGNORE:|"IGNORE" Return the response even when the status is outside 200-299
block func Called with response; response is closed upon return or error

Returns

Response -- The HTTP response

Errors

Exception Condition
Status The response is non-2xx and status: is not provided
Error A transport or protocol failure occurs
let client = Client()

let response = client.get https://api.example.com/users
  query: {page: 1 limit: 10}
  headers: {authorization: "Bearer token123"}
echo $response.status

let response = client.post https://api.example.com/users
  json:
    name: Alice
    age: 30

To keep the old behavior and inspect non-2xx responses directly, pass status: :IGNORE::

let response = client.get https://api.example.com/missing
  status: :IGNORE:
assert_eq $response.status 404

Request Options

body

Specifies the raw request body. Cannot be used together with json, lines, or multipart.

When a string or binary value is passed, it is sent as-is. When an iterable is passed, the values are streamed directly to the request body without adding any delimiters.

# Direct string body
let response = client.post https://api.example.com/data
  body: "raw text data"
  headers: {"content-type": "text/plain"}

# Streaming without delimiters (useful for binary data)
let response = client.post https://api.example.com/stream
  body: ["chunk1", "chunk2", "chunk3"]
  headers: {"content-type": "application/octet-stream"}

json

Specifies the request body as a Do value that will be automatically serialized to JSON. Cannot be used together with body, lines, or multipart.

let response = client.post https://api.example.com/users
  json: {name: "Alice", email: "alice@example.com"}

lines

Streams the request body from an iterable, adding a newline after each element. Cannot be used together with body, json, or multipart. Unlike body which accepts any value, lines requires an iterable.

let response = client.post https://api.example.com/data
  lines:
    - first line
    - second line
    - third line

# Sends: "first line\nsecond line\nthird line\n"

multipart

Builds a multipart/form-data request body from an iterable of part specs. Cannot be used together with body, json, or lines.

Each part must provide name and either body or, when the HTTP extension is built with its json feature, json. filename and content_type are optional.

let response = client.post https://api.example.com/upload
  multipart:
    - name: file
      filename: report.txt
      content_type: text/plain
      body: b"report contents"
    - name: metadata
      json:
        kind: report

Multipart part bodies accept:

  • Str for text fields
  • Bin for binary fields
  • iterable/input values for streaming uploads such as files opened in binary mode

When a part uses json:, the value is serialized the same way as a top-level request json: body. The part content_type defaults to application/json if omitted.

The request sets the multipart content-type header automatically, including the boundary parameter. Do not set content-type manually on multipart requests.

import fs:
  - open

open report.bin rb do |file|
  client.post https://api.example.com/upload
    multipart:
      - name: file
        filename: report.bin
        content_type: application/octet-stream
        body: $file

Binary file mode matters here: text-mode file iteration is line-oriented, while binary mode yields raw chunks suitable for uploads.

headers

Specifies request headers as a dictionary. Duplicate header names can be specified by repeating keys.

Header values are normally stringified. If a value is a DateTime, it is formatted as an HTTP-date (IMF-fixdate), which is useful for headers such as If-Modified-Since.

let response = client.get https://api.example.com/users
  headers:
    authorization: Bearer token123
    "user-agent": MyApp/1.0
    accept: application/json
    accept: application/json+verbose
import time:
  - DateTime

let response = client.get https://api.example.com/archive
  headers:
    "if-modified-since": DateTime.from_unix(1700000000)
  status: :IGNORE:

query

Specifies URL query parameters as a dictionary. Duplicate parameter names can be specified by repeating keys.

let response = client.get https://api.example.com/users
  query:
    page: 1
    limit: 10
    search: alice
    sort: name
    sort: age