HTTP
Native-fetch HTTP for TypeScript apps that you actually enjoy writing. No Axios. No magic globals. One tiny runtime dep. Errors are typed — not stringly-typed exceptions — so handling a 404 looks like if (error.isNotFound) instead of parsing a status code out of a thrown object.
You can be making requests within ten seconds of yarn adding it, because the package ships a pre-built http instance you can import and call. When you outgrow that — when you need a base URL, an auth header, a retry policy — you graduate to your own configured instance without changing a single call site.
Highlighted features
Ready-to-go singleton
Import http and start calling http.get(url) — no setup, no config, no boilerplate. Outgrow it later without changing call sites.
Typed data + error results
Every call returns a discriminated union — data on success, error on failure. No try/catch, no casts, no thrown values mid-render. TypeScript narrows the happy path for you.
Cancellation built in
Every returned promise carries a .cancel() method, or pass an external AbortSignal. Cancelled requests resolve with error.isAborted = true — no rejected-promise noise.
Smart GET deduplication + retry
Two concurrent calls to the same URL share one underlying fetch. Retry with configurable backoff and optional jitter — opt in per request or per instance.
Cache + interceptors
Plug any CacheDriver-compatible store for GET caching. before() shapes outgoing requests; after() runs on both success and error results — perfect for global toasts, refresh-token flows, and logging.
Resource for RESTful CRUD
Subclass Resource, set endpoint = “users”, and you get typed list / get / create / update / delete / publish — zero boilerplate, full type inference end to end.
Install
npm install @mongez/httpyarn add @mongez/httppnpm add @mongez/httpRuns anywhere fetch, AbortController, and TextDecoder are available — modern browsers, Node 18+, Bun, Deno. The only runtime dep is @mongez/concat-route for path joining.
Quick peek
import { http } from "@mongez/http";
const { data, error } = await http.get<User[]>( "https://api.example.com/users",);
if (error) { console.error(error.message); return;}
// `data` is `User[]` here — TypeScript narrows automatically.console.log(data.length, "users");The package ships a ready-to-use http singleton — import it and call it, no new, no config. The {data, error} result type means HTTP failures don’t throw. Typed error predicates like error.isNotFound / error.isUnauthorized / error.isValidationError are documented in error handling.
When you’re ready: bootstrap your own instance
Most apps want a base URL, an auth header, maybe a retry policy. Create one configured instance and reuse it everywhere:
import { Http, setCurrentHttp } from "@mongez/http";
export const http = new Http({ baseURL: import.meta.env.VITE_API_URL, auth: () => { const token = localStorage.getItem("token"); return token ? `Bearer ${token}` : null; },});
setCurrentHttp(http); // lets Resource classes pick it up lazily// anywhere else in your appimport { http } from "./lib/http";
const { data } = await http.get<User[]>("/users"); // hits VITE_API_URL/usersNeed a one-off variant? Don’t new Http() again — extend() returns a fresh instance with merged config:
const adminHttp = http.extend({ baseURL: "https://admin.api.com" });Where to go next
- HTTP client — every request method, options, and config field
- Error handling — the
HttpErrorpredicate cheat sheet - Resource — RESTful CRUD subclasses
- Caching — GET cache configuration and drivers
- Interceptors —
before()/after()and lifecycle events - Streaming — SSE, NDJSON, and raw streams
- Recipes — file uploads, React Query, multi-tenant clients