Composable HTTP request builder and executor for Supabase services.
Requests are built as plain maps using a threading-friendly API, then
executed through a supabase.core.transport/Transport. The default
transport wraps Hato; tests and integrators can swap it.
A request map contains:
:method — HTTP method keyword (:get :post :put :patch :delete):url — fully resolved URL string:headers — map of header name to value:query — map of query parameter name to value:body — request body (map, string, bytes, File, InputStream, or nil):multipart — vector of multipart parts (mutually exclusive with :body):response-as — :string (default), :byte-array, :stream, :reader:decoder — fn from raw body to parsed body (default JSON for :string):error-parser — fn [status body headers service] → anomaly map:log? — emit debug/error log lines for this request:timeout — per-request timeout (ms):transport — explicit transport instance (overrides client transport):service — originating service keyword (:auth, :storage, etc.):client — reference to the client map(require '[supabase.core.http :as http])
;; Build and execute a request
(-> (http/request client)
(http/with-service-url :auth-url "/signup")
(http/with-method :post)
(http/with-body {:email "user@example.com" :password "secret"})
(http/execute))
;; => {:status 200, :body {...}, :headers {...}} on success
;; => anomaly map on HTTP error (status >= 400)
;; Streaming response (no decoding)
(-> (http/request client)
(http/with-service-url :storage-url "/object/bucket/path")
(http/with-response-as :stream)
(http/execute))
;; => {:status 200, :body #object[java.io.InputStream ...], :headers {...}}
;; Multipart upload
(-> (http/request client)
(http/with-service-url :storage-url "/object/bucket/path")
(http/with-method :post)
(http/with-multipart [{:name "file" :content (io/file "a.png")
:content-type "image/png" :filename "a.png"}])
(http/execute))
Composable HTTP request builder and executor for Supabase services.
Requests are built as plain maps using a threading-friendly API, then
executed through a [[supabase.core.transport/Transport]]. The default
transport wraps Hato; tests and integrators can swap it.
## Request map
A request map contains:
- `:method` — HTTP method keyword (`:get` `:post` `:put` `:patch` `:delete`)
- `:url` — fully resolved URL string
- `:headers` — map of header name to value
- `:query` — map of query parameter name to value
- `:body` — request body (map, string, bytes, File, InputStream, or nil)
- `:multipart` — vector of multipart parts (mutually exclusive with `:body`)
- `:response-as` — `:string` (default), `:byte-array`, `:stream`, `:reader`
- `:decoder` — fn from raw body to parsed body (default JSON for `:string`)
- `:error-parser` — fn `[status body headers service]` → anomaly map
- `:log?` — emit debug/error log lines for this request
- `:timeout` — per-request timeout (ms)
- `:transport` — explicit transport instance (overrides client transport)
- `:service` — originating service keyword (`:auth`, `:storage`, etc.)
- `:client` — reference to the client map
## Usage
(require '[supabase.core.http :as http])
;; Build and execute a request
(-> (http/request client)
(http/with-service-url :auth-url "/signup")
(http/with-method :post)
(http/with-body {:email "user@example.com" :password "secret"})
(http/execute))
;; => {:status 200, :body {...}, :headers {...}} on success
;; => anomaly map on HTTP error (status >= 400)
;; Streaming response (no decoding)
(-> (http/request client)
(http/with-service-url :storage-url "/object/bucket/path")
(http/with-response-as :stream)
(http/execute))
;; => {:status 200, :body #object[java.io.InputStream ...], :headers {...}}
;; Multipart upload
(-> (http/request client)
(http/with-service-url :storage-url "/object/bucket/path")
(http/with-method :post)
(http/with-multipart [{:name "file" :content (io/file "a.png")
:content-type "image/png" :filename "a.png"}])
(http/execute))(execute req)Executes the request synchronously through the configured transport.
Returns a response map on success (status < 400) or an anomaly map on error.
When :log? is true on the request map or the client, a debug line is
emitted on dispatch and an error/debug line on completion.
Executes the request synchronously through the configured transport. Returns a response map on success (status < 400) or an anomaly map on error. ## Logging When `:log?` is true on the request map or the client, a debug line is emitted on dispatch and an error/debug line on completion.
(execute! req)Like execute, but throws an ex-info on error.
The anomaly map is attached as the ex-data of the thrown exception.
Like [[execute]], but throws an `ex-info` on error. The anomaly map is attached as the ex-data of the thrown exception.
(execute-async req)Executes the request asynchronously. Returns a CompletableFuture
that resolves to the same value execute would return.
Executes the request asynchronously. Returns a `CompletableFuture` that resolves to the same value [[execute]] would return.
(merge-query-param req key value)(merge-query-param req key value sep)Appends value to the existing value at key in the query map,
joined by sep (default ,). When the key is absent, sets it to
value. Useful for PostgREST-style stacked filters.
Appends `value` to the existing value at `key` in the query map, joined by `sep` (default `,`). When the key is absent, sets it to `value`. Useful for PostgREST-style stacked filters.
(request client)Initializes a request map from a client, pre-populating auth headers.
The request starts with :method :get and includes the client's global
headers plus authorization and apikey headers derived from the client.
Initializes a request map from a client, pre-populating auth headers. The request starts with `:method :get` and includes the client's global headers plus `authorization` and `apikey` headers derived from the client.
(with-body req body)Sets the request body.
Behaviour:
content-type: application/json is set.byte[] / File / InputStream → passed through as-is. Caller is
responsible for setting content-type.Sets the request body.
Behaviour:
- Map → JSON-encoded and `content-type: application/json` is set.
- String → passed through as-is.
- `byte[]` / `File` / `InputStream` → passed through as-is. Caller is
responsible for setting `content-type`.
- nil → cleared.(with-decoder req decoder)Sets a custom body decoder. decoder is a 1-arg fn taking the raw
response body and returning the parsed value. Applied only when
:response-as is :string (the default).
Pass identity to receive the raw string body without JSON parsing.
Sets a custom body decoder. `decoder` is a 1-arg fn taking the raw response body and returning the parsed value. Applied only when `:response-as` is `:string` (the default). Pass `identity` to receive the raw string body without JSON parsing.
(with-error-parser req parser)Installs a custom error parser. parser is a 4-arg fn
[status body headers service] returning an anomaly map. Default is
supabase.core.error/from-http-response.
Service modules (auth, storage, postgrest, functions) use this to enrich anomalies with service-specific error codes.
Installs a custom error parser. `parser` is a 4-arg fn `[status body headers service]` returning an anomaly map. Default is [[supabase.core.error/from-http-response]]. Service modules (auth, storage, postgrest, functions) use this to enrich anomalies with service-specific error codes.
(with-headers req headers)Merges additional headers into the request. Later values override earlier ones.
Merges additional headers into the request. Later values override earlier ones.
(with-logging req)(with-logging req on?)Enables or disables structured request/response logging for this
request. When the request map (or its client) has :log? true,
clojure.tools.logging emits a debug line on dispatch and on
success, plus an error line on failure.
Enables or disables structured request/response logging for this request. When the request map (or its client) has `:log? true`, `clojure.tools.logging` emits a debug line on dispatch and on success, plus an error line on failure.
(with-method req method)Sets the HTTP method for the request.
Sets the HTTP method for the request.
(with-multipart req parts)Attaches a multipart payload. Mutually exclusive with :body.
parts is a vector of part maps shaped like:
{:name "file" ;; form field name (required)
:content <File | InputStream | byte[] | String> ;; required
:content-type "image/png" ;; optional
:filename "a.png" ;; optional, becomes filename=
:encoding "UTF-8"} ;; optional charset
Hato is responsible for assembling the multipart body and setting the
multipart/form-data content-type with boundary.
Attaches a multipart payload. Mutually exclusive with `:body`.
`parts` is a vector of part maps shaped like:
{:name "file" ;; form field name (required)
:content <File | InputStream | byte[] | String> ;; required
:content-type "image/png" ;; optional
:filename "a.png" ;; optional, becomes filename=
:encoding "UTF-8"} ;; optional charset
Hato is responsible for assembling the multipart body and setting the
`multipart/form-data` content-type with boundary.(with-query req params)Merges query parameters into the request. Later values override earlier ones.
Merges query parameters into the request. Later values override earlier ones.
(with-response-as req as)Sets how the transport should coerce the response body.
:string (default) — UTF-8 string. Decoded by with-decoder
(JSON by default).:byte-array — raw bytes. No decoding.:stream — java.io.InputStream. No decoding. Caller closes.:reader — java.io.Reader. No decoding. Caller closes.Non-string bodies skip the default JSON decode step.
Sets how the transport should coerce the response body.
- `:string` (default) — UTF-8 string. Decoded by [[with-decoder]]
(JSON by default).
- `:byte-array` — raw bytes. No decoding.
- `:stream` — `java.io.InputStream`. No decoding. Caller closes.
- `:reader` — `java.io.Reader`. No decoding. Caller closes.
Non-string bodies skip the default JSON decode step.(with-service-url req service-url-key path)Sets the request URL by resolving a service URL key from the client and
appending path. service-url-key is a keyword like :auth-url.
Sets the request URL by resolving a service URL key from the client and appending `path`. `service-url-key` is a keyword like `:auth-url`.
(with-timeout req ms)Per-request timeout in milliseconds.
Per-request timeout in milliseconds.
(with-transport req t)Overrides the transport used for this request.
Overrides the transport used for this request.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |