Skip to content

Client

An HTTP client.

A client holds the configuration and any session state its requests share.

A client's methods are named for HTTP verbs -- get, head, post, put, patch, delete, options, trace, connect -- and take the arguments documented on get and post.

Request options

body

Sends the request body as given. Mutually exclusive with json, lines and multipart.

A Str or Bin is sent as-is. An iterable is streamed, its values written back to back with nothing between them.

client.post https://api.example.com/data
  body: "raw text data"
  headers: {"content-type": "text/plain"}

client.post https://api.example.com/stream
  body: ["chunk1", "chunk2", "chunk3"]
  headers: {"content-type": "application/octet-stream"}

json

Serializes a Do value as the JSON request body. Mutually exclusive with body, lines and multipart.

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

lines

Streams the body from an iterable, writing a newline after each element. Mutually exclusive with body, json and multipart. Unlike body, this requires an iterable.

client.post https://api.example.com/data
  lines:
    - first line
    - second line
# Sends: "first line\nsecond line\n"

multipart

Builds a multipart/form-data body from an iterable of part specs. Mutually exclusive with body, json and lines.

Each part needs name and either body or -- when the extension is built with its json feature -- json. filename and content_type are optional; a json part's content_type defaults to application/json.

A part body accepts a Str, a Bin, or an iterable to stream, such as a file opened in binary mode. Binary mode matters: text-mode file iteration is line-oriented, while binary mode yields the raw chunks an upload wants.

The content-type header, boundary included, is set automatically. Do not set it yourself on a multipart request.

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
      - name: metadata
        json:
          kind: report

headers

Request headers, as a dict. Repeating a key sends the header more than once.

Values are stringified, except a time.DateTime, which is formatted as an HTTP-date (IMF-fixdate) -- what a header such as if-modified-since expects.

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

query

URL query parameters, as a dict. Repeating a key sends the parameter more than once.

client.get https://api.example.com/users
  query:
    page: 1
    sort: name
    sort: age

Constructor

Client … -> Client

Builds a client.

Browser builds accept only func; any other option raises RuntimeError.

Parameters

NameTypeDescription
:unix_socket? Str Path to a Unix domain socket to connect through. Unix only.
:proxy? (Str | (url.Url | nil)) Proxy for every request made by this client.
:cookies? Bool Give the client a cookie jar, so cookies it receives are replayed on later requests.
: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 identity. Defaults to empty. Passing it without identity raises ValueError.
:invalid_certs? :DANGER_ACCEPT: Pass :DANGER_ACCEPT: to disable TLS certificate validation. This is dangerous -- it defeats the point of TLS, so reserve it for testing.
:unix_socket

This is not container-transparent: it connects to a socket on the host running the Do process, not through the shell agent's container filesystem and network translation.

:proxy

By default the client honors the system proxy environment (HTTP_PROXY, HTTPS_PROXY, NO_PROXY). Passing nil explicitly disables proxy detection entirely rather than selecting the default.

:cookies

Cookie state belongs to the one client and is shared with nothing else, the module-level request functions included.

Example

let client = Client()

Client cookies: true do |session|
  session.post https://example.com/login
  session.get https://example.com/dashboard do |resp|
    echo $resp.status

Client func … -> R

Builds a client and calls func with it. The client is closed when func returns.

Browser builds accept only func; any other option raises RuntimeError.

Parameters

NameTypeDescription
:unix_socket? Str Path to a Unix domain socket to connect through. Unix only.
:proxy? (Str | (url.Url | nil)) Proxy for every request made by this client.
:cookies? Bool Give the client a cookie jar, so cookies it receives are replayed on later requests.
: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 identity. Defaults to empty. Passing it without identity raises ValueError.
:invalid_certs? :DANGER_ACCEPT: Pass :DANGER_ACCEPT: to disable TLS certificate validation. This is dangerous -- it defeats the point of TLS, so reserve it for testing.
func ((Client) -> R) Called with the Client. Omit to receive the client instead.

Methods

close()

Closes the client, releasing its connection pool.

Closing an already-closed client does nothing.

get url … -> Response

Makes a request without a body.

head, delete, options, trace and connect take the same arguments.

Parameters

NameTypeDescription
url (Str | url.Url) URL to request.
:headers? Dict[Value, Value] Request headers -- see headers.
:query? Dict[Value, Value] Query parameters -- see query.
:status? (:IGNORE: | "IGNORE") Pass :IGNORE: to return the response even when its status is outside 200..=299, instead of raising Status.

Errors

Exception Condition
Status The response is non-2xx and status: was not passed
Error A transport or protocol failure

Example

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

get[R] url block … -> R

Makes a request without a body and calls block with the response. The response is closed when block returns.

Parameters

NameTypeDescription
url (Str | url.Url) URL to request.
:headers? Dict[Value, Value] Request headers -- see headers.
:query? Dict[Value, Value] Query parameters -- see query.
:status? (:IGNORE: | "IGNORE") Pass :IGNORE: to return the response even when its status is outside 200..=299, instead of raising Status.
block ((Response) -> R) Called with the Response. Omit to receive the response instead.

post url … -> Response

Makes a request with a body.

put and patch take the same arguments. At most one of body, json, lines and multipart may be given.

Parameters

NameTypeDescription
url (Str | url.Url) URL to request.
:body? (Str | Bin) Request body -- see body.
:json? json.Encodable Request body, JSON-serialized -- see json.
:lines? Iterable[Value] Request body streamed with a newline after each element -- see lines.
:multipart? Iterable[Dict[{name: Str, ...}]] Multipart form parts -- see multipart.
:headers? Dict[Value, Value] Request headers -- see headers.
:query? Dict[Value, Value] Query parameters -- see query.
:status? (:IGNORE: | "IGNORE") Pass :IGNORE: to return the response even when its status is outside 200..=299, instead of raising Status.

Errors

Exception Condition
Status The response is non-2xx and status: was not passed
Error A transport or protocol failure

Example

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

post[R] url block … -> R

Makes a request with a body and calls block with the response. The response is closed when block returns.

Parameters

NameTypeDescription
url (Str | url.Url) URL to request.
:body? (Str | Bin) Request body -- see body.
:json? json.Encodable Request body, JSON-serialized -- see json.
:lines? Iterable[Value] Request body streamed with a newline after each element -- see lines.
:multipart? Iterable[Dict[{name: Str, ...}]] Multipart form parts -- see multipart.
:headers? Dict[Value, Value] Request headers -- see headers.
:query? Dict[Value, Value] Query parameters -- see query.
:status? (:IGNORE: | "IGNORE") Pass :IGNORE: to return the response even when its status is outside 200..=299, instead of raising Status.
block ((Response) -> R) Called with the Response. Omit to receive the response instead.