npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@americanexpress/fetch-enhancers

v1.1.5

Published

Set of enhancers to extend fetch

Downloads

121

Readme

A library of middleware for enhancing Fetch.

Health Check

👩‍💻 Hiring 👨‍💻

Want to get paid for your contributions to @americanexpress/fetch-enhancers?

Send your resume to [email protected]

📖 Table of Contents

🤹‍ Usage

Installation

npm install --save @americanexpress/fetch-enhancers

Fetch Enhancers

Each fetch enhancer follows the same pattern:

  • Called with any arguments required for configuration fetchEnhancer(configuration)
  • Return a function which takes a fetch client as the sole argument fetchEnhancer(configuration)(fetch)

createTimeoutFetch [Server & Browser]

import { createTimeoutFetch } from '@americanexpress/fetch-enhancers';

createTimeoutFetch makes use of the AbortController to abort requests which exceed the given time limit.

Configuring

createTimeoutFetch takes a single argument which sets the default timeout.

const enhancedTimeoutFetch = createTimeoutFetch(6e3)(fetch);

When called, the enhanced fetch will accept an additional option, timeout, allowing for the default timeout value to be overridden for a single request.

const slowRequest = timeoutFetch('https://example.com/some-slow-api', { timeout: 10e3 });

Example

import { createTimeoutFetch } from '@americanexpress/fetch-enhancers';

// set your default timeout
const timeoutFetch = createTimeoutFetch(6e3)(fetch);

// Then use timeoutFetch as you would normally
const request = timeoutFetch('https://example.com');
request.then((response) => response.json())
  .then((data) => {
    console.log(data);
  });

// each request can override the default timeout
const fastRequest = timeoutFetch('https://example.com/fast', { timeout: 1e3 });

createRetryFetch [Server & Browser]

import { createRetryFetch } from '@americanexpress/fetch-enhancers';

Configuring

createRetryFetch accepts the an object with the following configuration: an optional maxRetry (default 3), and an optional back off strategy function:

const enhancedRetryFetch = createRetryFetch()(fetch);

Optional retry count and back off strategy function that accepts the current retry count:

const enhancedRetryFetch = createRetryFetch({
  maxRetry: 5,
  backoffStrategy: (n) => new Promise((res) => { setTimeout(res, n * 1000); }),
})(fetch);

Example

import { createRetryFetch } from '@americanexpress/fetch-enhancers';

const retryFetch = createRetryFetch()(createTimeoutFetch(5e3)(fetch));

// Then use retryFetch as you would normally
const request = retryFetch('https://example.com');
request.then((response) => response.json())
  .then((data) => {
    // do something with data
  });

createBrowserLikeFetch [Server only]

import { createBrowserLikeFetch } from '@americanexpress/fetch-enhancers';

createBrowserLikeFetch is for use on the server only. It enables the forwarding of cookies and headers from the request made to the host server to trusted outbound requests made during a server side render. Cookies which are returned are stored for the life of the host servers requests allowing those cookies to be included, when valid, on subsequent requests.

Configuring

createBrowserLikeFetch accepts the following named arguments:

headers

Object containing any headers to be included on fetch requests.

An example of how you could build the headers

const parseHeaders = (req) => ({
  Referer: url.format({
    protocol: req.protocol,
    hostname: req.hostname,
    pathname: req.path,
  }),
  cookie: req.headers.cookie,
});

const headers = parseHeaders(req);
const fetchWithRequestHeaders = createBrowserLikeFetch({
  headers,
  hostname: req.hostname,
  res, // Express response
  trustedURLs: [/^https:\/\/(www\.){0,1}(.*\.)example\.com[#/:?]{0,1}/],
})(mockFetch);
hostname

Hostname which should be derived from the Host HTTP header. Used to determine if set setCookie will be called. If using Express this can be retrieved from the req object.

res

Typically this would be an Express response object. createBrowserLikeFetch makes use of the cookie function to set cookies on the response.

If you wish to provide your own function to set cookies, use setCookie.

res.cookie() function provided by express requires this to be set to the context of the express middleware.

setCookie

This takes precedence over res.cookie provided in the res argument.

setCookie(name, value [, options])

A callback function invoked when a fetch response contains cookies with a domain which matches to the given hostname. This can be used to set the cookie on a response object.

setCookie is called with the same options as though it's the Express response cookie function. If you are passing in your own setCookie function it is important to note that the maxAge option will be in milliseconds.

If desired you can use setCookie to add additional checks or modify options passed to req.cookie.

const buildStringURIEncodingSetCookie = (res) => (name, value, options) => {
  res.cookie(name, value, { ...options, encode: String });
};

const fetchWithRequestHeaders = createBrowserLikeFetch({
  headers,
  hostname: req.hostname,
  setCookie: (name, value, options) => res.cookie(name, value, {
    ...options, encode: String,
  }),
  trustedURLs: [/^https:\/\/(www\.){0,1}(.*\.)example\.com[#/:?]{0,1}/],
})(mockFetch);
trustedURLs

A list of regular expressions used to test the first argument given to fetch when making a request. If the test is successful the enhanced fetch will include provided cookies.

const trustedURLs = [
  /^https:\/\/api\.example\.com[#/:?]{0,1}/,
  /^https:\/\/another\.example\.com[#/:?]{0,1}/,
  // or, more permissively all subdomains, including none
  /^https:\/\/(www\.){0,1}(.*\.)example\.com[#/:?]{0,1}/,
];

As these are regular expressions, be careful to consider values that you also do not want matched (ex: https://example.com.evil.tld/pwned).

trustedDomains

Renamed to trustedURLs. Usage of trustedDomains is deprecated, but values are added to those of trustedURLs until the next breaking version.

Example

const parseHeaders = (req) => ({
  Referer: url.format({
    protocol: req.protocol,
    hostname: req.hostname,
    pathname: req.path,
  }),
  cookie: req.headers.cookie,
  'some-header': req.headers['some-header'] || '1234',
});

const fetchWithRequestHeaders = createBrowserLikeFetch({
  headers: parseHeaders(req),
  hostname: req.hostname,
  res, // Express response
  trustedURLs: [/^https:\/\/(www\.){0,1}(.*\.)example\.com[#/:?]{0,1}/],
})(mockFetch);

fetchWithRequestHeaders('https://example.com', {
  credentials: 'include',
});

Composing fetch enhancers

You can chain together multiple enhancers to build a specific enhanced fetch client

import { createTimeoutFetch } from '@americanexpress/fetch-enhancers';
import { yourFetch } from './safeFetch';

const timeoutFetch = createTimeoutFetch(6e3)(fetch);
const myTimeoutFetch = yourFetch(/* options for configuring yourFetch */)(timeoutFetch);

// use the enhanced fetch as you would normally
const response = myTimeoutFetch('https://example.com');

You can also use Redux's compose function

import { compose } from 'redux';
import { createTimeoutFetch } from '@americanexpress/fetch-enhancers';
import { yourFetch } from './safeFetch';

const enhancedFetch = compose(
  yourFetch(),
  createTimeoutFetch(6e3)
)(fetch);

// Then use the enhanced fetch as you would normally
const request = enhancedFetch('https://example.com');
request.then((response) => response.json())
  .then((data) => {
    // do something with data
  });

Creating your own fetch enhancer

Each enhancer must return a function which accepts fetch as a single argument.

const strictCookieFetch = ({ allowSameOrigin }) => (nextFetch) => {
  (url, arguments_) => nextFetch(url, {
    ...arguments_,
    // use config arg allowSameOrigin
    credentials: allowSameOrigin ? 'same-origin' : 'omit',
  });
};

const safeFetch = strictCookieFetch()(fetch);

🏆 Contributing

We welcome Your interest in the American Express Open Source Community on Github. Any Contributor to any Open Source Project managed by the American Express Open Source Community must accept and sign an Agreement indicating agreement to the terms below. Except for the rights granted in this Agreement to American Express and to recipients of software distributed by American Express, You reserve all right, title, and interest, if any, in and to Your Contributions. Please fill out the Agreement.

Please feel free to open pull requests and see CONTRIBUTING.md to learn how to get started contributing.

🗝️ License

Any contributions made under this project will be governed by the Apache License 2.0.

🗣️ Code of Conduct

This project adheres to the American Express Community Guidelines. By participating, you are expected to honor these guidelines.