Client
Plugins

Plugins

feTS Client provides a plugin system that allows you hook into the request/response lifecycle.

  • onRequestInit - Called before the request is sent by the client
    • It has endResponse method that accepts a Response object to short-circuit the request
  • onFetch - Called when fetch is called by the client
    • You can change fetch options or change the fetch function
  • onResponse - Called after the request is handled by the router
    • It allows you to modify the response or throw an error to prevent the response from being returned

Cookies

In order to handle cookies seperately from the environment, you can use the useCookieStore plugin.

Note: This plugin is not needed for browsers

import { CookieStore, useClientCookieStore } from 'fets'
 
// Create a cookie store with a cookie string
const cookieStore = new CookieStore('')
 
const client = createClient<typeof someoas>({
  plugins: [useClientCookieStore(cookieStore)]
})

You can store cookies in a custom storage by using the events of CookieStore. It implements WHATWG Cookie Store which is documented on MDN; CookieStore documentation (opens in a new tab)

Retry on fail

You can install fetch-retry from npm and use it as a plugin.

import fetchRetry from 'fetch-retry'
 
export function useRetry(): ClientPlugin {
  return {
    onFetch({ fetchFn, setFetchFn }) {
      setFetchFn(fetchRetry(fetchFn))
    }
  }
}

HTTP Caching on non-browser environments

Usually server environments don't have browser's HTTP caching logic. So with fetchache, you can bring this behavior to the server-side environments.

fetchache needs a key value cache implementation to work. It can be Redis or a simple in-memory cache. The following example shows an example with in-memory cache.

import { fetchFactory, KeyValueCache } from 'fetchache'
import { ClientPlugin } from 'fets'
 
const mapForCache = new Map<string, any>()
 
const cache: KeyValueCache = {
  async get(key) {
    return _map.get(key)
  },
  async set(key, value) {
    _map.set(key, value)
  },
  async delete(key) {
    _map.delete(key)
  }
}
 
const useCache: ClientPlugin = {
  onFetch({ fetchFn, setFetchFn }) {
    setFetchFn(
      fetchFactory({
        fetch: fetchFn,
        cache,
        Response
      })
    )
  }
}

Add Authorization header

import { ClientPlugin } from 'fets'
 
export function useAuth(token: string): ClientPlugin {
  return {
    onRequestInit({ requestInit }) {
      requestInit.headers = {
        ...requestInit.headers,
        Authorization: `Bearer ${token}`
      }
    }
  }
}

Calculate request duration

import { ClientPlugin } from 'fets'
 
export function useDuration(): ClientPlugin {
  const startTimeByRequestInit = new WeakMap<RequestInit, number>()
  return {
    onRequestInit({ requestInit }) {
      startTimeByRequestInit.set(requestInit, Date.now())
    },
    onResponse({ response }) {
      const start = startTimeByRequestInit.get(response.requestInit)
      if (start) {
        const duration = Date.now() - Number(start)
        console.log(`Request took ${duration}ms`)
      }
    }
  }
}

HTTP/2 on Node.js

HTTP/2 is automatically handled by the most of environments but Node.js needs a special treatment.

You can use fetch-h2 to enable HTTP/2 on Node.js.

import fetchH2 from 'fetch-h2'
 
const client = createClient<typeof someoas>({
  fetch: fetchH2 as typeof fetch
})