Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.goldsky.com/llms.txt

Use this file to discover all available pages before exploring further.

Auditable HTTP Requests with “fetch”

Make HTTP requests that are recorded as spans on the task run. This is how Compose apps interact with off-chain systems — every ctx.fetch call, its URL, and its response are captured in the run’s event log, so the behavior of your app is auditable after the fact. For example, if you have an oracle that is advertised as being driven by an aggregate of several well-known price feeds, users of dApps built with it can audit the calls made to determine their prices, ensuring the price logic is fair and works as advertised. ctx.fetch wraps the native fetch and adds a few Compose-specific behaviors: the response is parsed as JSON (with a text fallback), each call is recorded as an OpenTelemetry span, successful results are cached by a deterministic idempotency key so replays after a crash don’t re-hit the remote server, and the request runs on a dedicated HTTP client pool isolated from Compose’s internal traffic.
fetch<T = unknown>(
  url: string,
  fetchConfigOrRetryConfig?: FetchConfig | ContextFunctionRetryConfig,
  retryConfig?: ContextFunctionRetryConfig
): Promise<T | undefined>
Where FetchConfig is:
export interface FetchConfig {
  method?: string;
  headers?: Record<string, string>;
  body?: Record<string, unknown> | string;
}
And ContextFunctionRetryConfig is:
type ContextFunctionRetryConfig = {
  max_attempts: number;
  initial_interval_ms: number;
  backoff_factor: number;
};
By default, ctx.fetch does not retry on failure (max_attempts defaults to 1). If you want automatic retries with exponential backoff, pass a ContextFunctionRetryConfig explicitly — see the “Request with Custom Retry Configuration” example below.

Response handling

ctx.fetch reads the response body as JSON and returns the parsed object. If the body is not valid JSON, it falls back to returning the raw text. Non-2xx responses throw an error that includes the status code, status text, and response body — so you do not need to check response.ok yourself. Because of this, the return type is the decoded body, not a Response object.

Examples

Basic GET Request

import { TaskContext } from "compose";

export async function main({ fetch }: TaskContext) {
  const data = await fetch("https://api.example.com/data");
  return data;
}

POST Request with JSON Body

If body is an object, ctx.fetch JSON-encodes it for you. Pass a string if you want to send a raw body (e.g. form-encoded or pre-serialized JSON).
To call another task in the same app, use ctx.callTask — you don’t need to go through HTTP unless you’re hitting an HTTP-triggered task externally.
import { TaskContext } from "compose";

export async function main({ fetch }: TaskContext) {
  const result = await fetch("https://api.example.com/submit", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: "Bearer token123",
    },
    body: {
      name: "John Doe",
      email: "john@example.com",
    },
  });

  return result;
}

Request with Custom Retry Configuration

import { TaskContext } from "compose";

export async function main({ fetch }: TaskContext) {
  const data = await fetch(
    "https://unreliable-api.com/data",
    {
      method: "GET",
      headers: { "User-Agent": "Compose/1.0" },
    },
    {
      max_attempts: 5,
      initial_interval_ms: 2000,
      backoff_factor: 1.5,
    }
  );

  return data;
}

Next Steps

Collections

Manage state across tasks and task runs with collections.

EVM

Interact with EVM blockchains and smart contracts.