Client
Introduction
Client
is a class that allows you to configure the server connection. It initializes the entire library’s
subsystems, such as queues
, caches
, and interceptors
. It also allows you to create (based on its settings) the
requests necessary to execute requests. This way the data and information flow remains locked inside a given client; it
is isolated and does not affect other clients.
It was designed to be used as a singleton, where Client
helps us create a global structure for making server requests
without duplicating logic in different parts of the application. In this approach, we can easily create a solid
structure and architecture for an application. This also facilitates test maintenance by dividing the necessary
configurations and types.
Purpose
- Orchestrates the components and flow of the library
- Creates requests to provide global setup and environment
- Isolates clients from other clients and their events
Related guides
Initialization
import { Client } from "@hyper-fetch/core";
export const client = new Client({ url: "http://localhost:3000" });
Setting defaults
Because Hyper Fetch components are created inside Client, you can set global or default system values on it.
Request default setup
We can use the setRequestDefaultOptions
method to specify the defaults for every created request.
type RequestOptionsType<GenericEndpoint,AdapterOptions,RequestMethods> = {
abortKey: string;
auth: boolean;
cache: boolean;
cacheKey: string;
cacheTime: number;
cancelable: boolean;
deduplicate: boolean;
deduplicateTime: number;
disableRequestInterceptors: boolean;
disableResponseInterceptors: boolean;
effectKey: string;
endpoint: GenericEndpoint;
garbageCollection: number;
headers: HeadersInit;
method: RequestMethods;
offline: boolean;
options: AdapterOptions;
queueKey: string;
queued: boolean;
retry: number;
retryTime: number;
}
Add them by:
const request = client.setRequestDefaultOptions((options) => {
if (options.method === "POST") {
return { timeout: 1000, withCredentials: true };
} else {
return options;
}
});
Adapter defaults setup
Adapter options may vary depending on the adapter you use.
We can use the setAdapterDefaultOptions
method to specify the defaults for every request.
Default HTTP adapter options:
{
timeout: number;
withCredentials: boolean;
responseType: "text" | "document" | "arraybuffer" | "blob" | "json";
}
Add them by:
const request = client.setAdapterDefaultOptions({ timeout: 1000, withCredentials: true });
Features
Authentication
To send authenticated requests, set up the onAuth
interceptor. Set up the request with the auth
option set to
true. Read more about authentication here.
Pre-Request Interceptor
Use the onRequest
client method if you need to use the pre-request interceptor to modify the request before it’s sent.
Post-Request Interceptors
There are several methods for intercepting a response from a request:
onError
which is triggered on request error response.onSuccess
which is triggered on request success response.onResponse
which is triggered on any response.
We can modify received data with these interceptors before it will be emitted to other sub-systems.
Query Params
Client has a built-in query params encoding function; you can modify its options or provide your own function. Use the
setQueryParamsConfig
method and the options listed below.
{
arrayFormat: bracket | index | comma | separator | bracket-separator | none;
arraySeparator: string;
dateParser: (value: QueryParamType) => string;
encode: boolean;
objectParser: (value: QueryParamType) => string;
skipEmptyString: boolean;
skipNull: boolean;
strict: boolean;
}
To change the encoding function, use the setStringifyQueryParams
method.
client.setStringifyQueryParams((value: string) => encode(value));
Header Mapper
By default, the header mapper behaves very simply: it checks if the content is FormData or JSON, and provides correct
headers to the request. You can create much more advanced setups with the setHeaderMapper
. It allows you to define
custom logic that will be triggered before every request made in the client.
Payload Mapper
The payload mapper’s default responsibility is to check if data is an instance of FormData or not. Based on this, you can stringify non-FormData values or just pass the FormData to the request to be made. This allows file upload to be supported out of the box.
Typescript
Client has two generic types.
class Client<GlobalErrorType, AdapterOptions>
GlobalErrorType
defines the error type used in all the requests. It should consist of anError
type and your defaultServerErrorType
. For some request’s individual error types, you can set up aLocalErrorType
for each request.AdapterOptions
is the generic responsible for shaping options passed to the adapter. Most likely you will change it only when you provide your custom adapter.
Components
Cache
Handles data storages and persistence. Can be adjusted with options when initializing Client
.
Adapter
Handles all requests within Client
. Can be replaced with setAdapter
method.
SubmitDispatcher
Handles the mutation requests and queueing. Can be adjusted with options when initializing the client.
FetchDispatcher
Handles the fetching requests and queueing. Can be adjusted with options when initializing the client.
AppManager
Handles the app focus and online state. Can be adjusted with options when initializing the client.
RequestManager
Handles additional events and cancellation of requests. Can be adjusted with options when initializing the client.
LoggerManager
Handles the logging systems for debugging.
Parameters
Configuration options
{
adapter: (request: RequestInstance, requestId: string, DO_NOT_USE?: [object Object]) => Promise<ResponseReturnType<any, any, any>>;
appManager: (client: C) => C[appManager];
cache: (client: C) => C[cache];
fetchDispatcher: (client: C) => C[submitDispatcher];
submitDispatcher: (client: C) => C[fetchDispatcher];
url: string;
}