| name | mongez-http-client |
| description | @mongez/http `Http` class — making HTTP/API requests and **replacing axios/fetch** with `get`, `post`, `put`, `patch`, `delete`, `head`, `options`, `request`, concurrent `all`/`race`, `invalidate`/`invalidateAll`, `extend`. Covers **typing responses with a generic** (`http.get<User>()` — the default is `unknown`, so `data.first_name` won't type-check without it) and narrowing the `{ data, error }` discriminated union. Per-request `.cancel()` and external `AbortSignal`. Full `HttpConfig` (`baseURL`, `auth`, `timeout`, `putToPost`, `serializer`, `fetchCache`, `dedupeKey`) and `RequestOptions` (`params`, `signal`, `responseType`, `data`, `throw`).
|
Http class
How to get an Http to call
@mongez/http exports a pre-built http singleton — use it directly. Do not construct a new Http per call.
import { http } from '@mongez/http';
const { data, error } = await http.get<User[]>('https://api.example.com/users');
import { Http, setCurrentHttp } from '@mongez/http';
export const http = new Http({ baseURL: '...', auth: getToken });
setCurrentHttp(http);
const adminHttp = http.extend({ baseURL: 'https://admin.api.com' });
❌ Anti-pattern — do not write this:
import { Http } from '@mongez/http';
const { data } = await new Http().get(url);
new Http() with no config is functionally identical to the http singleton. Just import { http } from '@mongez/http' instead.
Type the response — always pass a generic
Every request method is generic with a default of unknown:
get<T = unknown>(path, options?): CancellablePromise<HttpResult<T>>. If you
omit the type, data is unknown and TypeScript rejects any property
access — data.first_name won't compile. Always pass the expected response
type (this is the single most common mistake when migrating from axios/fetch):
const { data } = await http.get<User>('/users/1');
const { data: users } = await http.get<User[]>('/users');
const { data: user } = await http.post<User>('/users', { name: 'Alice' });
HttpResult<T> is a discriminated union — { data: T; error: null } on
success, { data: null; error: HttpError } on failure. Narrow on error first
so data becomes the non-null T:
const { data, error } = await http.get<User>('/users/1');
if (error) return;
console.log(data.first_name);
Reach for the generic, not an as User cast or any — it types the result end
to end (and flows through all/race and Resource too).
Common patterns
import { http } from '@mongez/http';
const { data, error } = await http.get<User[]>('/users');
if (error) { return; }
console.log(data);
const { data: user } = await http.post<User>('/users', { name: 'Alice' });
const { data: bytes } = await http.get<ArrayBuffer>(
'https://example.com/image.png',
{ responseType: 'arrayBuffer' },
);
const req = http.get('/slow');
req.cancel('component unmounted');
const { signal } = new AbortController();
const { data } = await http.get('/users', { signal });
Class signature
class Http {
constructor(config?: HttpConfig)
get<T>(path: string, options?: RequestOptions): CancellablePromise<HttpResult<T>>
post<T>(path: string, data?: HttpData, options?: RequestOptions): CancellablePromise<HttpResult<T>>
put<T>(path: string, data?: HttpData, options?: RequestOptions): CancellablePromise<HttpResult<T>>
patch<T>(path: string, options?: RequestOptions): CancellablePromise<HttpResult<T>>
delete<T>(path: string, options?: RequestOptions): CancellablePromise<HttpResult<T>>
head(path: string, options?: RequestOptions): CancellablePromise<HttpResult<null>>
options<T>(path: string, options?: RequestOptions): CancellablePromise<HttpResult<T>>
request<T>(method: HttpMethod | string, path: string, data?: HttpData, options?: RequestOptions): CancellablePromise<HttpResult<T>>
stream<T>(path: string, options?: StreamRequestOptions): CancellableAsyncIterable<T>
all<T>(requests: CancellablePromise<T>[]): CancellablePromise<T[]>
race<T>(requests: CancellablePromise<T>[]): CancellablePromise<T>
invalidate(key: string): Promise<void>
invalidateAll(): Promise<void>
extend(overrides: HttpConfig): Http
getConfig(): Readonly<HttpConfig>
before(fn: BeforeInterceptor): this
after<T>(fn: AfterInterceptor<T>): this
on(event: string, handler: HttpEventHandler): this
off(event: string, handler: HttpEventHandler): this
}
HttpConfig
interface HttpConfig {
baseURL?: string
auth?: string | ((req: OutgoingRequest) => string | null | undefined)
putToPost?: boolean
putMethodKey?: string
timeout?: number
headers?: Record<string, string>
params?: HttpParams
cache?: boolean | HttpCacheConfig
retry?: HttpRetryConfig
publishKey?: string
credentials?: RequestCredentials
mode?: RequestMode
keepalive?: boolean
redirect?: RequestRedirect
fetchCache?: RequestCache
serializer?: (data: unknown) => { body: BodyInit; contentType: string }
dedupeKey?: (url: string, params?: HttpParams) => string
}
RequestOptions
interface RequestOptions {
params?: HttpParams
headers?: Record<string, string>
signal?: AbortSignal
cache?: boolean | Omit<HttpCacheConfig,'driver'> & { driver?: CacheDriver }
cacheKey?: string
retry?: boolean | Partial<HttpRetryConfig>
throw?: boolean
timeout?: number
data?: unknown
responseType?: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'stream'
onDownloadProgress?: (event: DownloadProgressEvent) => void
onUploadProgress?: (event: UploadProgressEvent) => void
credentials?: RequestCredentials
mode?: RequestMode
keepalive?: boolean
redirect?: RequestRedirect
fetchCache?: RequestCache
}
React — cancel on unmount
function useUser(id: number) {
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
const req = http.get<User>(`/users/${id}`);
req.then(({ data, error }) => {
if (error?.isAborted) return;
if (data) setUser(data);
});
return () => req.cancel('unmounted');
}, [id]);
return user;
}
React Query integration
import { useQuery } from '@tanstack/react-query';
useQuery({
queryKey: ['users', params],
queryFn: ({ signal }) =>
http.get('/users', { params, signal }).then(({ data, error }) => {
if (error) throw error;
return data;
}),
});
Multi-tenant: different Http per resource
const publicHttp = new Http({ baseURL: 'https://api.example.com/public' });
const privateHttp = new Http({ baseURL: 'https://api.example.com/v2', auth: getToken });
export const articlesResource = new ArticlesResource().useHttp(publicHttp);
export const ordersResource = new OrdersResource().useHttp(privateHttp);
putToPost (Laravel file uploads)
Useful for Laravel APIs that don't accept PUT/PATCH natively with file uploads:
const http = new Http({ baseURL, putToPost: true, putMethodKey: '_method' });
const fd = new FormData();
fd.append('avatar', file);
fd.append('name', 'Alice');
await http.put('/users/1', fd);