Skip to main content
Version: v7.0.0

Client

Read the API Reference »

Client is the central class for configuring your server connection in Hyper Fetch. It initializes all core subsystems—such as queues, cache, and interceptors—and provides a unified way to create and manage requests based on its configuration. By keeping all data and logic encapsulated within a single client instance, you ensure that each client remains isolated and independent from others.


Purpose
  1. Builder for all of the requests
  2. Central place for all the default settings
  3. Handles authentication and interceptors
  4. Place where all sub-modules are initialized

Initialization

The client is initialized with the createClient function.

import { createClient } from "@hyper-fetch/core";

export const client = createClient({ url: "http://localhost:3000" });
More about setup
Learn different ways and options to initialize the client

Available methods

Methods
Name Description
triggerPlugins(key, data)
setRequestIdMapper(callback)
setQueryKeyMapper(callback)
setLogger(callback)
Set the new logger instance to the Client
setLogLevel(severity)
Set the logger severity of the messages displayed to the console
setEnableGlobalMocking(isMockerEnabled)
Set globally if mocking should be enabled or disabled for all client requests.
setDebug(enabled)
This method enables the logger usage and display the logs in console
setCacheKeyMapper(callback)
setAdapter(adapter)
Set custom http adapter to handle graphql, rest, firebase or others
setAbortKeyMapper(callback)
Key setters
removePlugin(plugin)
Remove plugins from Client
removeOnSuccessInterceptors(callbacks)
Method for removing listeners on success.
removeOnResponseInterceptors(callbacks)
Method for removing listeners on request.
removeOnRequestInterceptors(callbacks)
Method for removing listeners on request.
removeOnErrorInterceptors(callbacks)
Method for removing listeners on error.
removeOnAuthInterceptors(callbacks)
Method for removing listeners on auth.
onSuccess(callback)
Method for intercepting success responses.
onResponse(callback)
Method for intercepting any responses.
onRequest(callback)
Method of manipulating requests before sending the request.
onError(callback)
Method for intercepting error responses. It can be used for example to refresh tokens.
onAuth(callback)
Method of manipulating requests before sending the request. We can for example add custom header with token to the request which request had the auth set to true.
hydrate(hydrationData, options)
Hydrate your SSR cache data
createRequest(_USE_DOUBLE_INITIALIZATION)
Create requests based on the Client setup
clear()
Clears the Client instance and remove all listeners on it's dependencies
addPlugin(plugin)
Add persistent plugins which trigger on the request lifecycle

Detailed methods docs
Check all available methods and their descriptions

Features

Here are some of the most important features available in the Client class.

Builder approach

The Client is designed to be used as a builder of requests, serving as the global entry point for server communication throughout your application. This approach prevents duplicated logic, promotes a consistent architecture, and makes it easier to maintain and test your code by centralizing configuration and types.

  1. createRequest()

The createRequest method is the main method for creating templates for the API connectivity. We use the builder pattern to create a request object which contain crucial information about the request - endpoint, method, etc.

Each request keep the reference to the client, so it can access the global settings.

import { createClient } from "@hyper-fetch/core";

const client = createClient({ url: "http://localhost:3000" });

const getUser = client.createRequest<{ response: User }>()({ endpoint: "/users/1" });

console.log(getUser);
Request
More about the request and how to use it

  1. Authentication

To send authenticated requests, set up the onAuth interceptor. Set up the request with the auth option set to true.

import { createClient } from "@hyper-fetch/core";
import { store } from "./store"; // Your state management store

export const client = createClient({ url: "http://localhost:3000" }).onAuth((request) => {
// Get the auth token from your store
const state = store.getState();
const authToken = state.auth.token;

// Add the token to the request headers
return request.setHeaders({
...request.headers,
Authorization: `Bearer ${authToken}`,
});
});

// Create an authenticated request
export const getUsers = client.createRequest()({
endpoint: "/users",
auth: true, // This enables the onAuth interceptor
});
Authentication guide
Learn how to set up authentication for your application

  1. Interceptors

Interceptors are a powerful feature that allows you to modify requests before they're sent or responses before they are processed within other core modules.

They can modify the request before it's sent or the response after it's received, depending on the type of interceptor.

Request Interceptor

  • onRequest() - allows to modify the request before it's sent giving ability to modify its data
  • onAuth() - allows to modify the request with auth: true before it's sent, giving ability to pass custom auth headers or other any options

Response Interceptor

There are several methods for intercepting a response from a request:

  • onResponse() - intercepts any response after it's received to modify it's body
  • onError() - intercepts the error response after it's received to modify it's body
  • onSuccess() - intercepts the success response after it's received to modify it's body

We can modify received data with these interceptors before it will be emitted to other sub-systems.

import { createClient } from "@hyper-fetch/core";

export const client = createClient({ url: "http://localhost:3000" })
// Add request interceptor
.onRequest((request) => {
// Add custom headers to all requests
return request.setHeaders({
...request.headers,
"x-custom-header": "custom-value",
});
})
// Add response interceptor
.onResponse(async (response, request) => {
// Log all responses
console.log(`Response for ${request.endpoint}:`, response);
return response;
})
// Add error interceptor
.onError(async (errorResponse, request) => {
// Handle specific error responses
if (errorResponse.status === 401 && !request.used) {
// Implement token refresh logic
// Set Used allows you to prevent infinite loops of retries
return request.setUsed(true).send();
}
return errorResponse;
});
Interceptors guide
Learn how to set up interceptors for your application and when they can be used

  1. Global settings

Every module is initialized inside of the Client class. This is a perfect place to store and control global settings for the adapter, cache, requests or other modules.

import { createClient } from "@hyper-fetch/core";

export const client = createClient({
url: "http://localhost:3000",
});

client.adapter.setRequestDefaults({
retries: 3, // Retry failed requests 3 times
cacheTime: 5 * 60 * 1000, // Cache data for 5 minutes
staleTime: 60 * 1000, // Data becomes stale after 1 minute

// Adapter options
options: {
timeout: 10000, // 10 seconds timeout for all requests
},
});

// These global settings can be overridden for specific requests
export const getUser = client.createRequest()({
endpoint: "/users/:id",
method: "GET",
timeout: 5000, // Override the global timeout of 10000 for this request
});
Global defaults guide
Learn how to set global defaults for the client and requests

  1. Plugins

Plugins are a powerful feature that allows you to extend the functionality of the client. They can be used to listen to the events happening inside of the Hyper Fetch.

import { createClient } from "@hyper-fetch/core";
import { Plugin } from "@hyper-fetch/core";
import { DevtoolsPlugin } from "@hyper-fetch/plugin-devtools";

// Add the official devtools plugin
export const client = createClient({ url: "http://localhost:3000" })
.setDebug(true)
.addPlugin(
DevtoolsPlugin({
appName: "My Application",
}),
);

// Create a custom plugin
const loggingPlugin = new Plugin({
name: "logging-plugin",
})
.onRequestStart(({ request }) => {
console.log(`Request started: ${request.method} ${request.endpoint}`);
})
.onRequestSuccess(({ response, request }) => {
console.log(`Request succeeded: ${request.method} ${request.endpoint}`, response.data);
})
.onRequestError(({ response, request }) => {
console.error(`Request failed: ${request.method} ${request.endpoint}`, response.error);
});

// Add the custom plugin to the client
client.addPlugin(loggingPlugin);

  1. Hydration

We can hydrate the client with the data from the server. This is a powerful feature that allows us to pass the data from the server to the client for the SSR use cases.

// Server-side code
import { createClient } from "@hyper-fetch/core";

export const client = createClient({ url: "http://localhost:3000" });
const userRequest = client.createRequest()({ endpoint: "/users/1" });

// Fetch data on the server
const response = await userRequest.send();

// Dehydrate the response for client hydration
const dehydratedData = userRequest.dehydrate({ response });

// Pass dehydratedData to the client (e.g., as props or through a global state)

// *****************************************************
// *****************************************************
// Client-side code
// *****************************************************
// *****************************************************

import { createClient } from "@hyper-fetch/core";
import { useFetch } from "@hyper-fetch/react";

export const client = createClient({ url: "http://localhost:3000" });

// Hydrate the client with server data
client.hydrate([dehydratedData]);

// In your React component
function UserProfile() {
// Data will be available immediately from cache, no loading state needed
const { data } = useFetch(client.createRequest()({ endpoint: "/users/1" }), {
revalidate: false, // Prevent automatic refetching
});

return <div>{data?.name}</div>;
}

TypeScript

Most important type passed to the createClient is the error type. It is a global error type, being used like a default for any request errors. It is later combined with the "local error" type of the requests creating the union. This way we handle generic errors from the server (global) as well as some validation/business (local) errors for given endpoint.

Enhancing TypeScript DX

It is important to use the eslint plugin to get the best typescript experience. We enhance the abilities of the object generics to provide you with the best possible DX.

import { createClient, AdapterType } from "@hyper-fetch/core";

// Define your global error type
interface ClientErrorType {
message: string;
code: number;
}

const client = createClient<{ error: ClientErrorType }>();
  • error defines the global/default error type used in all the requests. It should consist of an Error type and your default ServerErrorType. It is propagated down to the createRequest method, serving as a default for the globalError type.

  • adapter is the generic responsible for shaping options passed to the adapter. Most likely you will change it only when you provide your custom adapter.

Modules

Client is a place where all the subsystems are initialized. Here is a diagram of the client and its subsystems:


See Also

Request
Handles request template creation and execution.
Cache
Handles data storages and persistence.
Adapter
Handles all requests within Client. Can be replaced with setAdapter method.
Dispatcher
Handles the requests deduplication and queueing.
Managers
Handles the logging systems, app focus and online state, additional events and cancellation of requests.