4.0.0 • Published 3 years ago

@savvagent-os/tiny-fetch-interceptors v4.0.0

Weekly downloads
1
License
MIT
Repository
-
Last release
3 years ago

tiny-fetch-interceptors

tiny-fetch-interceptors is an isomorphic class-based means of extending fetch, either window.fetch or global.fetch in NodeJS.

tiny-fetch-interceptors enhances fetch with interceptors without polluting fetch itself. It does so by embracing a class-based approach. Interceptors consist of objects that include one or more functions which are processed in order. Functions that can be included in interceptor objects include request, requestError, response and/or responseError. Interceptors are simple to write and share. This repo includes standard interceptors for making JSON requests, handling response errors and receiving JSON responses.

Benefits of Approach

tiny-fetch-interceptors has the following benefits:

  • tiny - it is 2.2KB unminified.
  • global fetch, whether window.fetch or node-fetch remains untouched. It is not monkey patched.
  • class based - You can create more than one instance if necessary to accommodate different APIs. Naturally, instances are isolated.
  • interceptors can be swapped on the fly.
  • interceptors can be overloaded.
  • interceptors can be shared.
  • you can build complex solutions.

Dependencies

Global fetch is required. tiny-fetch-interceptors has been tested against window.fetch, node-fetch and isomorphic-fetch. NodeJS 6x or greater is required.

tiny-fetch-interceptors has been developed with modern Javascript. Your project must be able to consume EcmaScript modules or CommonJS in node.

Installation

tiny-fetch-interceptors can be installed with either npm or yarn.

yarn add @savvagent-os/tiny-fetch-interceptors

or

npm i @savvagent-os/tiny-fetch-interceptors -S

Use

Here are some ways of using tiny-fetch-interceptors.

You can use some interceptors included with tiny-fetch-interceptors.

import { FetchClient, jsonRequest, jsonResponse } from '@savvagent-os/tiny-fetch-interceptors';
const interceptors = [jsonRequest, jsonResponse];
const client = new FetchClient(interceptors);

const resp = await client.request('http://some.url/', fetchOptions = {});

You can create your own interceptors and add and remove them dynamically.

import { FetchClient } from '@savvagent-os/tiny-fetch-interceptors';
import { interceptor, interceptor1, interceptor2 } from '../interceptors';

const client = new FetchClient();

client register(interceptor);

//register interceptor1 ahead of interceptor
client.register(interceptor1, 0);

// register interceptor2 at the end of the interceptor chain
client.register(interceptor2)

// get the current interceptors
const interceptors = client.getInterceptors();

// remove an interceptor
client.unregister(interceptorId)

// remove all the interceptors - useful for testing
client.clear();

// make requests
const url = 'https://gitlab.com/projects';

client.request(url)
  .then(response => console.log('response', response))
  .catch(error => console.log('error', error))

Interceptors

Interceptors are objects that must have at least one of the following functions: request, requestError, response, responseError. Hopefully, the purpose of the functions is clear from the names.

Interceptors run in order. So if I had an interceptor designed to catch network errors, I would want that interceptor to the first interceptor in the interceptor chain.

Interceptor Internals

An interceptor is an object that has a unique id and includes one or more permitted functions.

export default {
  request(url, config = {}) {
    Object.assign(config, {headers: {Accept: 'application/json'}});
    return [url, config];
  },
  requestError(error) {
    return Promise.reject(error);
  },
  response(response) {
    // modify the response
    return response;
  },
  responseError(error) {
    return Promise.reject(error);
  }
  id: 'JSON_REQUEST'
};

You can create interceptors for various needs. For example, here's an audio interceptor:

export const audioInterceptor = {
  const source = audioCtx.createBufferSource();
  response(response) {
    return response.arrayBuffer()
      .then(buffer => audioCtx.decodeAudioData(buffer, decodedData => {
        source.buffer = decodedData;
        source.connect(audioCtx.destination);
      }))
      .then(() => source);
  }
  id: 'AUDIO_INTERCEPTOR'
}