0Z4C0
// navigation
// @ozaco/std

Fetch

An effect-native HTTP client — the familiar `fetch`, wrapped as a chainable operation with codec-aware body decoding.

import from@ozaco/std/fetch

std:fetch wraps the platform fetch as an effect operation. fetch(input, init?) returns a FetchDef.Operation — a Future<Response> you can yield* for the wrapped response, or drive straight to a body with a chained shortcut like .json<T>(), .body<T>() or .stream<T>() (each runs the request and reads the body in one step).

Body reading integrates the registered std:codec: body<T>() decodes the whole payload through the codec (auto-installing JsonCodec if none is present), stream<T>() pipes the body through the codec's streaming decoder for one value per chunk, and raw() hands back the undecoded byte stream. The classic json/text/arrayBuffer/blob/formData/bytes readers are all present too.

Errors follow the Result convention. Thrown faults — network errors, aborts, body-read failures — pass through untouched (reified via asFailure so their name and cause chain survive). The only tags fetch raises itself are 'http-status' (from .expect() on a non-ok response) and 'parse' (a response with no body). Cancellation is automatic: fetch forwards the running scope's abort signal, so a halted scope aborts the in-flight request. The underlying implementation is injectable via the fetchImpl context.

// on this page
01

Request

Make an HTTP request.

fn

fetch

Perform an HTTP request; returns a chainable operation resolving to a wrapped `Response`.

signature
const fetch: (input: RequestInfo | URL, init?: FetchDef.Init) => FetchDef.Operation

The returned Operation is itself a Future<Response>yield* it for the response, or call a body shortcut (.json(), .text(), .body(), .stream(), .raw(), …) to fetch and read in one step. Chain .expect() to fail with 'http-status' on any non-ok response. The scope's abort signal is forwarded automatically, so init.signal is intentionally disallowed.

// parameters
input: RequestInfo | URL
The request URL or a `Request`.
init?: FetchDef.Init
Standard `RequestInit`, minus `signal` (managed by the effect scope).
// returns A `FetchDef.Operation` — a `Future<Response>` with body-reading shortcuts.
example
import { fetch } from '@ozaco/std/fetch'

// fetch + decode JSON in one step
const user = yield* fetch('/api/user/42').json<User>()

// POST, then status-check and codec-decode the body
const res = yield* fetch('/api/todos', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: payload,
}).expect()
const created = yield* res.body<Todo>()
02

Context

Inject the underlying fetch implementation.

const

fetchImpl

Effect context holding the fetch implementation `fetch()` dispatches through.

signature
const fetchImpl: Context<FetchDef.Impl>

Defaults to globalThis.fetch. Override it for tests, SSR, or a custom transport with fetchImpl.set(impl) or fetchImpl.with(impl, op) in the running scope; fetch reads it via fetchImpl.get() so the default applies when unset.

example
import { fetchImpl } from '@ozaco/std/fetch'

yield* fetchImpl.with(mockFetch, function* () {
  const data = yield* fetch('/api/thing').json()
  // ...
})
03

Types

The `FetchDef` namespace: the response surface, the chainable operation, and configuration shapes.

iface

FetchDef.Response

The wrapped response: standard metadata plus effect-native, codec-aware body readers.

signature
interface Response {
  readonly native: globalThis.Response
  readonly ok: boolean
  readonly status: number
  readonly statusText: string
  readonly headers: Headers
  readonly url: string
  readonly redirected: boolean
  readonly bodyUsed: boolean
  readonly type: ResponseType
  json<T = unknown>(): Future<T>
  text(): Future<string>
  arrayBuffer(): Future<ArrayBuffer>
  blob(): Future<Blob>
  formData(): Future<FormData>
  bytes(): Future<Uint8Array>
  body<T = unknown>(): Future<T>
  stream<T = unknown>(): Future<Stream<T, StreamClose>>
  raw(): Future<Stream<Uint8Array, void>>
  expect(): Future<Response>
}

body<T>() decodes the whole payload through the registered codec (auto-installs JsonCodec if absent); stream<T>() yields one codec-decoded value per chunk; raw() is the undecoded byte stream; expect() fails with 'http-status' when the response is not ok.

iface

FetchDef.Operation

What `fetch` returns: a `Future<Response>` with the same body readers chained for one-step use.

signature
interface Operation extends Future<Response> {
  json<T = unknown>(): Future<T>
  text(): Future<string>
  arrayBuffer(): Future<ArrayBuffer>
  blob(): Future<Blob>
  formData(): Future<FormData>
  bytes(): Future<Uint8Array>
  body<T = unknown>(): Future<T>
  stream<T = unknown>(): Future<Stream<T, StreamClose>>
  raw(): Future<Stream<Uint8Array, void>>
  expect(): Operation
}

yield* it for the Response, or call a reader to run the request and read the body together. expect() returns another Operation, so it composes with the readers (e.g. fetch(url).expect().json()).

type

FetchDef.Init

Request init: a standard `RequestInit` with `signal` removed (the effect scope owns cancellation).

signature
type Init = Omit<RequestInit, 'signal'> & { signal?: never }
type

FetchDef.Impl

The underlying fetch implementation type, injectable via `fetchImpl`.

signature
type Impl = (input: RequestInfo | URL, init?: RequestInit) => Promise<globalThis.Response>
type

FetchDef.Error

Errors surfaced by fetch. Thrown faults pass through as `unknown`; the only tags it raises are `'http-status'` and `'parse'`.

signature
type Error = unknown