Skip to main content
Version: v8.0.0

Plugin

Read the API Reference »

Plugins allow you to connect into the lifecycle of the whole library. They expose different sets of the methods allowing you to react to particular events happening within a system.


Purpose
  1. Persists request side-effects
  2. Manipulates the lifecycle and allows hooking in

How to use?

The best way to create new plugin is to wrap the Plugin class into a function. This way you can pass in the configuration options and return the plugin instance.

Creating a new plugin
import { Plugin } from "@hyper-fetch/core";

const MyPlugin = ({ module }: { module: string }) => {
return new Plugin({
// Hook into creation of the request and log it
onRequestCreate: (request) => {
console.log(`[${module}] Request created`, request);
},
});
};

const client = new Client({
url: "https://api.example.com",
}).addPlugin(MyPlugin({ module: "MyApp" }));

Lifecycle Hooks

Plugins can subscribe to events across the entire Hyper Fetch system. Each hook method registers a callback and returns the Plugin instance for chaining.

Plugin Lifecycle

HookWhen it firesData received
onMountPlugin is added to the client via addPlugin(){ client }
onUnmountPlugin is removed via removePlugin(){ client }

Request Lifecycle

HookWhen it firesData received
onRequestCreateA new request instance is created via createRequest{ request }
onRequestTriggerA request is about to enter the dispatcher{ request }
onRequestStartThe adapter begins executing the request{ request }
onRequestSuccessThe adapter returns a successful response{ response, request }
onRequestErrorThe adapter returns an error response{ response, request }
onRequestFinishedThe request completes (success or error){ response, request }

Cache Lifecycle

HookWhen it firesData received
onCacheItemChangeA cache entry is created or updated{ cache, cacheKey, prevData, newData }
onCacheItemDeleteA cache entry is deleted{ cacheKey, cache }

Dispatcher Lifecycle

HookWhen it firesData received
onDispatcherQueueCreatedA new queue is created for an unseen queryKey{ dispatcher, queue }
onDispatcherItemAddedA request is added to a queue{ dispatcher, queue, queueItem }
onDispatcherItemDeletedA request is removed from a queue{ dispatcher, queue, queueItem }
onDispatcherQueueRunningA queue status changes ("running", "paused", "stopped"){ dispatcher, queue, status }
onDispatcherQueueDrainedA queue has no more pending requests{ dispatcher, queue }
onDispatcherQueueClearedAn entire queue is cleared{ dispatcher, queue }
onDispatcherClearedAll dispatcher storage is fully cleared{ dispatcher }

Adapter Lifecycle

HookWhen it firesData received
onAdapterFetchThe adapter is about to execute a network request{ request, requestId, adapter }
Example: using multiple hooks
const analyticsPlugin = new Plugin({ name: "analytics" })
.onRequestStart(({ request }) => {
performance.mark(`req-start-${request.queryKey}`);
})
.onRequestFinished(({ request, response }) => {
performance.mark(`req-end-${request.queryKey}`);
analytics.track("api_call", {
endpoint: request.requestOptions.endpoint,
success: response.success,
});
})
.onCacheItemChange(({ cacheKey, newData }) => {
console.log(`Cache updated: ${cacheKey}`);
});

client.addPlugin(analyticsPlugin);

Available methods

Methods
Name Description
trigger(method, data)
Invoke a registered plugin method by name. Used internally by the client to dispatch lifecycle events.
onUnmount(callback)
Callback that will be executed when plugin is unmounted
onRequestTrigger(callback)
Callback that will be executed when request gets triggered
onRequestSuccess(callback)
Callback that will be executed when response is successful
onRequestStart(callback)
Callback that will be executed when request starts
onRequestFinished(callback)
Callback that will be executed when response is finished
onRequestError(callback)
Callback that will be executed when response is failed
onRequestCreate(callback)
Callback that will be executed when request is created
onMount(callback)
Callback that will be executed when plugin is mounted
onDispatcherQueueRunning(callback)
Called when a dispatcher queue transitions to running, paused, or stopped
onDispatcherQueueDrained(callback)
Called when a dispatcher queue has no more pending requests
onDispatcherQueueCreated(callback)
Called when a new dispatcher queue is created
onDispatcherQueueCleared(callback)
Called when an entire dispatcher queue is cleared
onDispatcherItemDeleted(callback)
Called when an item is removed from a dispatcher queue
onDispatcherItemAdded(callback)
Called when a new item is added to a dispatcher queue
onDispatcherCleared(callback)
Called when the dispatcher storage is fully cleared
onCacheItemDelete(callback)
Called when a cache entry is deleted
onCacheItemChange(callback)
Called when a cache entry is created or updated
onAdapterFetch(callback)
Called when the adapter fetcher is about to execute a request
initialize(client)
Bind the plugin to a client instance. Called automatically when the plugin is added via client.addPlugin() .

Detailed methods docs
Check all available methods and their descriptions

Use cases

Logging

Plugins are heavily used by our devtools system to provide you with the live feed of what is happening in your application. They are great for logging, tracking, debugging and collecting metrics.

Persistence

There are many applications which require you to persist the state of the application. After reloading of the browser, app or server you need to keep up with the unsent requests.

Other solutions

There are many solutions for persistence, all of them approach this problem by introducing the sync mechanisms and local DBs. Among them you can find:

Hyper Fetch being the fetcher and a server state manager it is able to persist the state of the application. Not only that - it can store and persist requests which are not triggered yet - for example if you're in the offline mode.

Persisting requests

Having the request in the JSON format you can easily persist it in the persistent storage like local storage or any other storage you want.

Now imagine our app is offline, we close it and open it again. We can see that the request is still in the persistent storage and we can trigger it again.

Triggering requests

We don't have to do it for every request. To do so, we can attach into the Dispatcher lifecycle and on the onDispatcherItemAdded and onDispatcherItemDeleted events. With them we can add the stringified requests to the persistent storage.

Then on the start of the app we can trigger the requests from the persistent storage - this is because after refresh of the app Dispatchers do not have access to the persisted storage with our requests. At this time we can add the requests to the Dispatcher and trigger them or wait a bit waiting for the app to load.

Triggering requests

That's it! It is very simple concept, so keep that in mind when you're building your app.

info

We are waiting for your feedback on this feature. If you have any ideas or suggestions, please let us know. We are very determined to make it better and more useful for you.

There are few more aspects that could be worth mentioning like:

  1. Optimistic approach when you want to reflect all of the changes from your persisting requests inside of your UI.

  2. Topic of the connectivity itself. Your backend need to track all of the persistent requests with some kind of identifier from the frontend - possibly passed with a Header or a Query Parameter. To prevent duplicates and conflicts, you need to have some kind of a logic to prevent them.

These are large topics deserving their own guides, so stay tuned!


Parameters

Configuration options

PluginOptionsType
Name Type Description
data
PluginData
Data stored in a plugin
name
string
Name of the plugin