Fetch & Curl

FETCH makes HTTP requests from within OcaltQL. It operates in two modes — synchronous by default, or asynchronous with SET PROMISE. All modifiers are optional and can appear in any order. CURL is a direct alias for FETCH.

Sync vs Async

This is the most important distinction in FETCH.

SynchronousAFTER blocks until the fetch completes. The script cannot proceed until the response arrives. Simple and sequential, but the script pays the full wait cost at that line.

AsynchronousSET PROMISE starts the fetch in the background immediately. The script continues running. The variable is WAITING until the response arrives. You only block when you explicitly call WAIT FOR — and only if the fetch has not already resolved by then.

Synchronous — Script Blocks Here
FETCH "https://api.example.com/data" SET ?data
AFTER EMIT ?data
(* AFTER cannot run until FETCH completes *)
Asynchronous — Script Continues Immediately
FETCH "https://api.example.com/data" SET PROMISE ?data
AFTER EMIT "I ran immediately while fetch is still in progress"
AFTER WAIT FOR ?data SET ?result
AFTER EMIT ?result
(* Script runs freely until WAIT FOR — only blocks there *)
Parallel Async Fetches — Maximum Efficiency
FETCH "https://api1.com/data" SET PROMISE ?a
AND FETCH "https://api2.com/data" SET PROMISE ?b
AND FETCH "https://api3.com/data" SET PROMISE ?c
(* All three start simultaneously in the background *)

AFTER EMIT "Doing other work while fetches run"
AFTER CALCULATE 1 + 1 SET ?result

(* Now collect — if already resolved, no wait at all *)
AFTER WAIT FOR ?a SET ?a
AFTER WAIT FOR ?b SET ?b
AFTER WAIT FOR ?c SET ?c
AFTER EMIT ?a & ?b & ?c
Use sync when the next statement depends directly on the fetch result and there is nothing else to do in between. Use async with PROMISE when you have other work to do, or when you are firing multiple fetches and want them to run in parallel.

Basic FETCH

Without modifiers, FETCH performs a GET request and captures the response body.

GET Request
STRING "https://api.example.com/data" SET ?url
AFTER FETCH ?url SET ?data
AFTER EMIT ?data

Modifiers

All modifiers are optional and can appear in any order after the URL.

METHOD
FETCH ?url METHOD "post" SET ?posted
IP — Route Through Specific IP
FETCH ?url METHOD "post" IP "192.168.1.1" SET ?proxied
USER AGENT
FETCH ?url METHOD "post" USER AGENT "Mozilla/5.0" SET ?spoofed
TIMEOUT
FETCH ?url USER AGENT "CustomBot/1.0" TIMEOUT 10 SECONDS SET ?slow
HEADER — Multiple Headers
FETCH ?url METHOD "get" HEADER "Authorization: Bearer token" HEADER "X-Custom: value" SET ?headers

Request Body

The BODY modifier passes a request body. Set the appropriate HEADER alongside it for the content type.

Form Body
FETCH ?url METHOD "post" BODY "name=Alice&age=30" SET ?form
JSON Body
FETCH ?url METHOD "post" BODY '{"name":"Alice"}' HEADER "Content-Type: application/json" SET ?json

Download to File

INTO writes the response body directly to a file path. Side-effect only — no SET.

Fetch to File
FETCH ?url INTO "/root/downloaded.html"

Parsing the Response

PARSE JSON converts a raw JSON response string into an OcaltQL object.

FETCH and Parse JSON
FETCH ?url SET ?raw
AFTER PARSE JSON ?raw SET ?parsed
AFTER EMIT ?parsed("status")
AFTER EMIT ?parsed("data")

Split Status and Data Capture

To capture the HTTP status code and response body separately in one request, use WITH STATUS and WITH DATA.

Status and Body Separately
FETCH "https://api.example.com/data" SET ?responsecode WITH STATUS AND SET ?responsedata WITH DATA
AFTER EMIT ?responsecode
AFTER EMIT ?responsedata

CURL

CURL is a direct alias for FETCH. Every modifier and pattern available on FETCH works identically on CURL.

CURL — Basic
CURL ?url SET ?response
CURL — With Modifier
CURL ?url METHOD "get" SET ?simple
Modifier order does not matter. METHOD, HEADER, BODY, USER AGENT, IP, and TIMEOUT can appear in any combination and in any sequence after the URL.