🌐

Requests
request Http , response caching, safe build/parse hooks.

request Http {} declares a whole .thr component (extends="Task" required) as a single HTTP endpoint — one component per endpoint.

Declaring an endpoint

Static config (method/url/headers/query/body) covers the fixed shape; anything that varies per call flows through the optional buildRequest/parseResponse/parseError hooks.

GetPosts.thr
<script>
request Http {
  method: "GET",
  url: "https://jsonplaceholder.typicode.com/posts"
}

private function buildRequest(requestData: object): object {
  return { query: { "userId": requestData.userId } }
}

private function parseResponse(response: object): object {
  return { count: response.data.Count() }
}

private function parseError(response: object): object {
  return { message: "HTTP " + response.httpStatusCode.ToStr() }
}
</script>

<component extends="Task">
</component>

Calling it

When a component declares buildRequest, it also gets a generated prepareRequest(requestData) — call it before taskManager.run(task), on the calling thread, so nothing inside buildRequest ever risks a cross-thread rendezvous.

RequestDemoScreen.thr (excerpt)
task = CreateObject("roSGNode", "GetPosts")
task.callFunc("prepareRequest", { userId: 1 })   ' resolves buildRequest BEFORE the Task thread starts
taskManager.run(task)
taskManager.onResult(task, onPostsLoaded, onPostsFailed)

See Task manager for onResult and the app-wide onRequestSent/onResponseReceived interceptors. Both a promise-style (onResult) and an old-style (observeFieldScoped("result"/"error", ...)) consumption style are fully supported side by side.

Response caching — on by default

GET-only, backed by Roku's own cachefs:/. A request with no cache key at all still caches, purely following the server's own Cache-Control header — cache is only an override.

request Http {
  method: "GET",
  url: "https://api.example.com/catalog"
  ' caches automatically, following the server's own Cache-Control — no "cache" key needed
}

request Http {
  method: "GET",
  url: "https://api.example.com/live-price",
  cache: false   ' force caching OFF — always a real network request
}

request Http {
  method: "GET",
  url: "https://api.example.com/legacy-endpoint",
  cache: { ttlSeconds: 300 }   ' force this exact lifetime, ignoring Cache-Control
}

Crash safety

Every hook — buildRequest, parseResponse, parseError — is wrapped in a try/catch by the compiler. A buggy hook degrades to a synthesized fallback error (or the static base config, for buildRequest) instead of crashing the Task — surfaced via resolvedOptions.buildSucceeded/rawResponse.parseSucceeded for telemetry.

Reference implementation — apps/requests-demo

Every mechanism on this page has a router-mounted, scaled chapter in apps/requests-demo — 4 chapters (/declare-call through /parse-safety), reachable with REWIND/FAST-FORWARD once compiled and sideloaded. Each chapter shows a default, no-customization example alongside a deliberately different, customized one — e.g. DeclareCallDemo.thr's default button (promise-style onResult only) next to its customized button (the same request consumed via onResult AND the old-style observeFieldScoped("result"/"error", ...), side by side). This is the live, compiling reference for the whole page — see findings/requests-demo-app.md for what each chapter covers and findings/demo-app-conventions.md for the app-structure convention it follows.

⚠️ Not (yet) supported

  • ○ Only request Http {} is supported — any other Kind is a compile error.
  • ○ No retry logic, no cancellation, no request timeout — a hung transfer blocks only its own Task thread.
  • ○ No ETag/conditional-GET revalidation, no Expires header parsing — only Cache-Control: max-age.
  • ○ cache is not overridable per call via buildRequest — it's a property of the endpoint, not the call site.
  • ○ Bareword object keys inside a hook body's return value get case-folded by BrightScript at runtime — always quote a headers/query key that must match an API case-exactly.

Exact grammar: GRAMMAR.md. Full feature status: docs/features.md.