@jamx/http
v0.1.0
Published
Composable fetch helpers with interceptors, decoders, validators, and Railway-style results.
Maintainers
Readme
@jamx/http
Composable HTTP helpers built around fetch, interceptors, and Either-style
results.
Install
pnpm add @jamx/httpQuick Start
import {
composeInterceptors,
createMemoryCacheStore,
defaultFetch,
withAuth,
withCache,
withHeaders,
withRetry,
withTimeout,
} from "@jamx/http";
const cache = createMemoryCacheStore();
const handler = composeInterceptors(
withTimeout(250),
withHeaders({ accept: "application/json" }),
withAuth("demo-token"),
withJsonBody({ tenant: "team-a" }),
withCache({ store: cache }),
withRetry({ retries: 1 }),
)(defaultFetch);Core APIs
import {
createFetchHandler,
decodeJson,
defaultContext,
defaultFetch,
expectStatus,
} from "@jamx/http";
const customFetch = createFetchHandler(defaultContext);
const response = await defaultFetch("https://api.example.com/users/42");
const user = await decodeJson(expectStatus(response, 200), decodeUser);defaultContextis a reusableContextbacked byglobalThis.fetch.defaultFetchiscreateFetchHandler(defaultContext).createFetchHandler(...)is useful when you want to inject a mocked or custom fetch implementation.composeInterceptors(...)returns an executable handler with a composed result.
Decoder Helpers
Decoder helpers accept either a plain Response or an Either<..., Response>.
import { decodeJson, json, text, validate } from "@jamx/http";
import { z } from "zod";
const rawResponse = await fetch("https://api.example.com/users/42");
const userSchema = z.object({ id: z.number(), name: z.string() });
const bodyText = await text(rawResponse);
const bodyJson = await json(rawResponse);
const user = await decodeJson(rawResponse, decodeUser);
const userWithSchema = await validate(bodyJson, userSchema);When you already have an Either, upstream errors are preserved in the helper
result type.
Notes
withBaseUrlrebases request paths onto a configured base URL.- Put request-shaping interceptors like
withHeadersandwithAuthbeforewithCacheso cache keys can include the final request headers. withRetryonly retries idempotent methods by default. Passmethods: ["POST"]if you need to opt a write request into replay.validate(result, schema)accepts anEitherplus a Standard Schema compatible validator such as Zod.withTimeoutaborts the underlying request and returns aTimeoutErrorwhen the timeout elapses.TimeoutErrorextendsFetchError.
