fetch
The result of createFetch is a fetch instance typed with an HTTP schema,
mostly compatible with the native Fetch API.
Requests sent by the fetch instance have their URL automatically prefixed with the base URL of the instance. Default options are also applied to the requests, if provided.
fetch(input);
fetch(input, init);
Arguments:
-
input:
string | URL | FetchRequestThe resource to fetch, either a path, a URL, or another
FetchRequestrequest. If a path is provided, it is automatically prefixed with the base URL of the fetch instance when the request is sent. If a URL or a request is provided, it is used as is. -
init:
FetchRequestInitThe options to use for the request. If a path or a URL is provided as the first argument, this argument is required and should contain at least the method of the request. If the first argument is a
FetchRequest, this argument is optional. The options inherit from the nativeRequestInitinterface, with the following additional properties:-
method:
stringThe HTTP method to use for the request. Differently from the native Fetch API, this is required to ensure that requests are typed correctly.
-
baseURL:
string | undefinedThe base URL for the request. If provided, it will have preference over the default base URL of the fetch instance.
-
searchParams:
HttpSearchParamsSchema.Loose | undefinedThe search parameters to be sent with the request. If provided, it will have preference over the default search parameters of the fetch instance.
-
duplex:
'half' | undefinedThe duplex mode for the request. If set to
'half', the request body will be streamed. See Request streaming for more details.
-
Returns: Promise<FetchResponse>
A promise that resolves to a FetchResponse, which is typed with the
schema of the fetch instance.
import { HttpSchema } from '@zimic/http';
import { createFetch } from '@zimic/fetch';
interface User {
id: string;
username: string;
}
type Schema = HttpSchema<{
'/users': {
GET: {
request: {
searchParams: { query?: string };
};
response: {
200: { body: User[] };
404: { body: { message: string } };
500: { body: { message: string } };
};
};
};
}>;
const fetch = createFetch<Schema>({
baseURL: 'http://localhost:3000',
headers: { 'accept-language': 'en' },
});
const response = await fetch('/users', {
method: 'GET',
searchParams: { query: 'u' },
});
if (response.status === 404) {
return null; // User not found
}
if (!response.ok) {
throw response.error;
}
const users = await response.json();
return users; // User[]
fetch defaults
Fetch instances inherit from the native RequestInit
interface and can have default options applied to all requests made through them. On top of the native properties in
RequestInit, fetch instance also accept:
-
baseURL:
string | undefinedThe base URL for the fetch instance, which will be prepended to all request URLs.
-
searchParams:
HttpSearchParamsSchema.Loose | undefinedThe default search parameters to be sent with each request.
-
duplex:
'half' | undefinedThe duplex mode for the fetch instance. If set to
'half', the request body will be streamed. See Request streaming for more details.
import { HttpSchema } from '@zimic/http';
import { createFetch } from '@zimic/fetch';
interface Post {
id: string;
title: string;
}
type Schema = HttpSchema<{
'/posts': {
POST: {
request: {
headers: { authorization?: string };
body: { title: string };
};
response: {
201: { body: Post };
};
};
};
}>;
const fetch = createFetch<Schema>({
baseURL: 'http://localhost:3000',
// Setting defaults when creating the fetch instance
headers: {
'accept-language': 'en',
'cache-control': 'no-cache',
},
});
// Somewhere else in the code, you can update the defaults
fetch.headers.authorization = `Bearer ${accessToken}`;
@zimic/fetch@1.2.0Up to @zimic/fetch@1.1.x, the default options were available under the fetch.defaults property. Starting from 1.2.0,
you can access them directly on the fetch instance (e.g., fetch.headers instead of fetch.defaults.headers).
fetch.defaults is still available for backward compatibility, but it is deprecated and will be removed in the next
major release.
Related:
fetch.onRequest
A listener function that is called before sending each request.
Type: (request: FetchRequest.Loose) => Promise<Request> | Request
Arguments:
-
request:
FetchRequest.LooseThe request to be sent.
Returns: Promise<Request> | Request
The request to use, either a modified version of the original request or a new one.
import { createFetch } from '@zimic/fetch';
import { HttpSchema } from '@zimic/http';
interface User {
id: string;
username: string;
}
type Schema = HttpSchema<{
'/users': {
GET: {
request: {
searchParams: { page?: number; limit?: number };
};
response: {
200: { body: User[] };
};
};
};
}>;
const fetch = createFetch<Schema>({
baseURL: 'http://localhost:80',
});
fetch.onRequest = (request) => {
if (fetch.isRequest(request, 'GET', '/users')) {
const url = new URL(request.url);
url.searchParams.append('limit', '10');
const updatedRequest = new Request(url, request);
return updatedRequest;
}
return request;
};
Related:
fetch.onResponse
A listener function that is called after receiving each response.
Type: (response: FetchResponse.Loose) => Promise<Response> | Response
Arguments:
-
response:
FetchResponse.LooseThe response received from the server.
Returns: Promise<Response> | Response
The response to use, either a modified version of the original response or a new one.
import { HttpSchema } from '@zimic/http';
import { createFetch } from '@zimic/fetch';
interface User {
id: string;
username: string;
}
type Schema = HttpSchema<{
'/users': {
GET: {
response: {
200: {
headers: { 'content-encoding'?: string };
body: User[];
};
};
};
};
}>;
const fetch = createFetch<Schema>({
baseURL: 'http://localhost:80',
});
fetch.onResponse = (response) => {
if (fetch.isResponse(response, 'GET', '/users')) {
console.log(response.headers.get('content-encoding'));
}
return response;
};
Related:
fetch.loose
A loosely-typed version of fetch. This can be useful to make requests with fewer type constraints, such as in
onRequest and onResponse listeners.
fetch.loose(input);
fetch.loose(input, init);
Arguments:
-
input:
string | URL | FetchRequestThe resource to fetch, either a path, a URL, or another
FetchRequestrequest. If a path is provided, it is automatically prefixed with the base URL of the fetch instance when the request is sent. If a URL or a request is provided, it is used as is. -
init:
FetchRequestInitThe options to use for the request. If a path or a URL is provided as the first argument, this argument is required and should contain at least the method of the request. If the first argument is a
FetchRequest, this argument is optional. The options inherit from the nativeRequestInitinterface, with the following additional properties:-
method:
string | undefinedThe HTTP method to use for the request.
-
baseURL:
string | undefinedThe base URL for the request. If provided, it will have preference over the default base URL of the fetch instance.
-
searchParams:
HttpSearchParamsSchema.Loose | undefinedThe search parameters to be sent with the request. If provided, it will have preference over the default search parameters of the fetch instance.
-
duplex:
'half' | undefinedThe duplex mode for the request. If set to
'half', the request body will be streamed. See Request streaming for more details.
-
See our authentication guide for an example of how to
use fetch.loose.
fetch.Request
A constructor for creating a FetchRequest instance, which inherits from
the native Request and receives the same arguments as fetch.
new fetch.Request(input);
new fetch.Request(input, init);
Arguments:
-
input:
string | URL | FetchRequestThe resource to fetch, either a path, a URL, or another
FetchRequestrequest. If a path is provided, it is automatically prefixed with the base URL of the fetch instance when the request is sent. If a URL or a request is provided, it is used as is. -
init:
FetchRequestInit | undefinedThe options to use for the request. If a path or a URL is provided as the first argument, this argument is required and should contain at least the method of the request. If the first argument is a
FetchRequest, this argument is optional. The options inherit from the nativeRequestInitinterface, with the following additional properties:-
method:
stringThe HTTP method to use for the request.
-
baseURL:
string | undefinedThe base URL for the request. If provided, it will have preference over the default base URL of the fetch instance.
-
searchParams:
HttpSearchParamsSchema.Loose | undefinedThe search parameters to be sent with the request. If provided, it will have preference over the default search parameters of the fetch instance.
-
duplex:
'half' | undefinedThe duplex mode for the request. If set to
'half', the request body will be streamed. See Request streaming for more details.
-
Related:
fetch.isRequest
A type guard that checks if a request is a FetchRequest, was created by
the fetch instance, and has a specific method and path. This is useful to narrow down the type of a request before using
it.
fetch.isRequest(request, method, path);
Arguments:
-
request:
unknownThe request to check.
-
method:
stringThe method to check.
-
path:
stringThe path to check.
Returns: boolean
true if the request was created by the fetch instance and has the specified method and path; false otherwise.
import { HttpSchema } from '@zimic/http';
import { createFetch } from '@zimic/fetch';
interface User {
id: string;
username: string;
}
type Schema = HttpSchema<{
'/users': {
POST: {
request: {
headers: { 'content-type': 'application/json' };
body: { username: string };
};
response: {
201: { body: User };
};
};
};
}>;
const fetch = createFetch<Schema>({
baseURL: 'http://localhost:3000',
});
const request = new fetch.Request('/users', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ username: 'me' }),
});
if (fetch.isRequest(request, 'POST', '/users')) {
// request is a FetchRequest<Schema, 'POST', '/users'>
const contentType = request.headers.get('content-type'); // 'application/json'
const body = await request.json(); // { username: string }
}
fetch.isResponse
A type guard that checks if a response is a FetchResponse, was received
by the fetch instance, and has a specific method and path. This is useful to narrow down the type of a response before
using it.
fetch.isResponse(response, method, path);
Arguments:
-
response:
unknownThe response to check.
-
method:
stringThe method to check.
-
path:
stringThe path to check.
Returns: boolean
true if the response was received by the fetch instance and has the specified method and path; false otherwise.
Example:
import { HttpSchema } from '@zimic/http';
import { createFetch } from '@zimic/fetch';
interface User {
id: string;
username: string;
}
type Schema = HttpSchema<{
'/users': {
GET: {
request: {
searchParams: { query?: string };
};
response: {
200: { body: User[] };
};
};
};
}>;
const fetch = createFetch<Schema>({
baseURL: 'http://localhost:3000',
});
const response = await fetch('/users', {
method: 'GET',
searchParams: { query: 'u' },
});
if (fetch.isResponse(response, 'GET', '/users')) {
// response is a FetchResponse<Schema, 'GET', '/users'>
const users = await response.json(); // User[]
}
fetch.isResponseError
A type guard that checks if an error is a FetchResponseError related to a
FetchResponse received by the fetch instance with a specific method and
path. This is useful to narrow down the type of an error before handling it.
fetch.isResponseError(error, method, path);
Arguments:
-
error:
unknownThe error to check.
-
method:
stringThe method to check.
-
path:
stringThe path to check.
Returns: boolean
true if the error is a response error received by the fetch instance and has the specified method and path; false
otherwise.
import { HttpSchema } from '@zimic/http';
import { createFetch } from '@zimic/fetch';
interface User {
id: string;
username: string;
}
type Schema = HttpSchema<{
'/users': {
GET: {
request: {
searchParams: { query?: string };
};
response: {
200: { body: User[] };
400: { body: { message: string } };
500: { body: { message: string } };
};
};
};
}>;
const fetch = createFetch<Schema>({
baseURL: 'http://localhost:3000',
});
try {
const response = await fetch('/users', {
method: 'GET',
searchParams: { query: 'u' },
});
if (!response.ok) {
throw response.error; // FetchResponseError<Schema, 'GET', '/users'>
}
} catch (error) {
if (fetch.isResponseError(error, 'GET', '/users')) {
// error is a FetchResponseError<Schema, 'GET', '/users'>
const status = error.response.status; // 400 | 500
const { message } = await error.response.json(); // { message: string }
console.error('Could not fetch users:', { status, message });
}
}
Related: