Home

Awesome

Frisbee

Slack Status npm version npm downloads build status code coverage code style styled with prettier made with lass license

:heart: Love this project? Support <a href="https://github.com/niftylettuce" target="_blank">@niftylettuce's</a> FOSS on <a href="https://patreon.com/niftylettuce" target="_blank">Patreon</a> or <a href="https://paypal.me/niftylettuce">PayPal</a> :unicorn:

Modern fetch-based alternative to axios/superagent/request. Great for React Native.

New in v2.0.4++: baseURI is now optional and you can pass raw: true as a global or request-based option to get the raw fetch() response (e.g. if you want to use res.arrayBuffer() or any other method manually).

Table of Contents

Install

Node (Koa, Express, React Native, ...)

  1. Install the required package:

    npm install --save frisbee
    
  2. See usage example and API below

Browser

VanillaJS

  1. Load the package via <script> tag (note you will need to polyfill with required features):
<script crossorigin="anonymous" src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=es6,Array.from,Object.getOwnPropertyDescriptors,Object.getOwnPropertySymbols,Promise,Promise.race,Promise.reject,Promise.resolve,Reflect,Symbol.for,Symbol.iterator,Symbol.prototype,Symbol.species,Symbol.toPrimitive,Symbol.toStringTag,Uint8Array"></script>
<script src="https://unpkg.com/frisbee"></script>
<script type="text/javascript">
  (function() {
    // create a new instance of Frisbee
    var api = new Frisbee({
      baseURI: 'https://api.startup.com', // optional
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      }
    });

    // this is a simple example using `.then` and `.catch`
    api.get('/hello-world').then(console.log).catch(console.error);

    //
    // see the Usage section below in Frisbee's README for more information
    // https://github.com/niftylettuce/frisbee
    //
  })();
</script>
  1. See usage example and API below for a more complete example.

Bundler

  1. Install the required package:

    npm install frisbee
    
  2. Ensure that your environment is polyfilled with required features (e.g. use @babel/polyfill globally or a service like polyfill.io)

  3. See usage example and API below

Usage

Example

const Frisbee = require('frisbee');

// create a new instance of Frisbee
const api = new Frisbee({
  baseURI: 'https://api.startup.com', // optional
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  }
});

// this is a simple example using `.then` and `.catch`
api.get('/hello-world').then(console.log).catch(console.error);

// this is a more complex example using async/await and basic auth
(async () => {
  // log in to our API with a user/pass
  try {
    // make the request
    let res = await api.post('/v1/login');

    // handle HTTP or API errors
    if (res.err) throw res.err;

    // set basic auth headers for all
    // future API requests we make
    api.auth(res.body.api_token);

    // now let's post a message to our API
    res = await api.post('/v1/messages', { body: 'Hello' });

    // handle HTTP or API errors
    if (res.err) throw res.err;

    // now let's get a list of messages filtered by page and limit
    res = await api.get('/v1/messages', {
      body: {
        limit: 10,
        page: 2
      }
    });

    // handle HTTP or API errors
    if (res.err) throw res.err;

    // now let's logout
    res = api.post('/v1/logout');

    // handle HTTP or API errors
    if (res.err) throw res.err;

    // unset auth now since we logged out
    api.auth();

    // for more information on `fetch` headers and
    // how to send and expect various types of data:
    // <https://github.com/github/fetch>
  } catch (err) {
    console.error(err);
  }
})();

API

const Frisbee = require('frisbee');

Frisbee is a function that optionally accepts an argument options, which is an object full of options for constructing your API instance.

Upon being invoked, Frisbee returns an object with the following chainable methods:

Logging and Debugging

We highly recommend to use CabinJS as your Node.js and JavaScript logging utility (see Automatic Request Logging for complete examples).

Logging Requests and Responses

You can log both requests and/or responses made to fetch internally in Frisbee. Simply pass a logRequest and/or logResponse function.

logRequest accepts two arguments path (String) and opts (Object) and these two arguments are what we call fetch with internally (e.g. fetch(path, opts)):

const cabin = require('cabin');
const frisbee = require('frisbee');
const pino = require('pino')({
  customLevels: {
    log: 30
  },
  hooks: {
    // <https://github.com/pinojs/pino/blob/master/docs/api.md#logmethod>
    logMethod(inputArgs, method) {
      return method.call(this, {
        // <https://github.com/pinojs/pino/issues/854>
        // message: inputArgs[0],
        msg: inputArgs[0],
        meta: inputArgs[1]
      });
    }
  }
});

const logger = new Cabin({
  // (optional: your free API key from https://cabinjs.com)
  // key: 'YOUR-CABIN-API-KEY',
  axe: { logger: pino }
});

const api = new Frisbee({
  logRequest: (path, opts) => {
    logger.info('fetch request', { path, opts });
  }
});

logResponse accepts three arguments, the first two are the same as logRequest (e.g. path and opts), but the third argument is response (Object) and is the raw response object returned from fetch (e.g. const response = await fetch(path, opts)):

const cabin = require('cabin');
const frisbee = require('frisbee');
const pino = require('pino')({
  customLevels: {
    log: 30
  }
});

const logger = new Cabin({
  // (optional: your free API key from https://cabinjs.com)
  // key: 'YOUR-CABIN-API-KEY',
  axe: { logger: pino }
});

const api = new Frisbee({
  logResponse: (path, opts, res) => {
    logger.info('fetch response', { path, opts, res });
  }
});

Debug Statements

You can run your application with DEBUG=frisbee node app.js to output debug logging statements with Frisbee.

Common Issues

Required Features

This list is sourced from ESLint output and polyfilled settings through eslint-plugin-compat.

Frequently Asked Questions

How do I unset a default header

Simply set its value to null, '', or undefined – and it will be unset and removed from the headers sent with your request.

A common use case for this is when you are attempting to use FormData and need the content boundary automatically added.

Why do my form uploads randomly fail with React Native

This is due to a bug with setting the boundary. For more information and temporary workaround if you are affected please see facebook/react-native#7564 (comment).

Does this support callbacks, promises, or both

As of version 1.0.0 we have dropped support for callbacks, it now only supports Promises.

What is the fetch method

It is a WHATWG browser API specification. You can read more about at the following links:

Does the Browser or Node.js support fetch yet

Yes, a lot of browsers are now supporting it! See this reference for more information http://caniuse.com/#feat=fetch.

If my engine does not support fetch yet, is there a polyfill

Yes you can use the fetch method (polyfill) from whatwg-fetch or node-fetch.

By default, React Native already has a built-in fetch out of the box!

Can I make fetch support older browsers

Yes, but you'll need a promise polyfill for older browsers.

What is this project about

Use this package as a universal API wrapper for integrating your API in your client-side or server-side projects.

It's a better working alternative (and with less headaches; at least for me) – for talking to your API – than superagent and the default fetch Network method provide.

Use it for projects in Node, React, Angular, React Native, ...

It supports and is tested for both client-side usage (e.g. with Bower, Browserify, or Webpack, with whatwg-fetch) and also server-side (with node-fetch).

Why not just use superagent or fetch

See Background for more information.

Want to build an API back-end with Node.js

See Lad as a great starting point, and read this article about building Node.js API's with authentication.

Need help or want to request a feature

File an issue on GitHub and we'll try our best help you out.

Tests

This package is tested to work with whatwg-fetch and node-fetch.

This means that it is compatible for both client-side and server-side usage.

Development

  1. Fork/clone this repository
  2. Run npm install
  3. Run npm run watch to watch the src directory for changes
  4. Make changes in src directory
  5. Write unit tests in /test/ if you add more stuff
  6. Run npm test when you're done
  7. Submit a pull request

Background

The docs suggest that you use superagent with React Native, but in our experience it did not work properly, therefore we went with the next best solution, the Github fetch API polyfill included with React Native. After having several issues trying to use fetch and writing our own API wrapper for a project with it (and running into roadblocks along the way) – we decided to publish this.

Here were the issues we discovered/filed related to this:

We know that solutions like superagent exist, but they don't seem to work well with React Native (which was our use case for this package).

In addition, the authors of WHATWG's fetch API only support throwing errors instead of catching them and bubbling them up to the callback/promise (for example, with Frisbee any HTTP or API errors are found in the res.err object).

Therefore we created frisbee to serve as our API glue, and hopefully it'll serve as yours too.

Contributors

NameWebsite
Nick Baughhttp://niftylettuce.com/
Alexis Tyler
Assem-Hafez
Jordan Denison
James
Sampsa Saarela
Julien Moutte
Charles Soetan
Kesha Antonov
Ben Turley
Richard Evans
Hawken Rives
Fernando Montoya
Brent Vatne
Hosmel Quintana
Kyle Kirbatski
Adam Jenkins

Credits

License

MIT © Nick Baugh