tldr; Stripe-inspired API wrapper for WHATWG's fetch() method for making simple HTTP requests (alternative to superagent, request, axios).
If you're using
node-fetch
, you neednode-fetch@v1.5.3
to useform-data
with files properly (due to node-fetch/node-fetch#102) If you experience form file upload issues, please see facebook/react-native#7564 (comment).
- React Native Usage
- Browser and Server-Side Usage
- API
- Frequently Asked Questions
- Tests
- Development
- Background
- Contributors
- Credits
- License
- Install the required package (note that
react-native
provides us with afetch
implementation):
npm install --save frisbee
-
Import the package:
import Frisbee from 'frisbee';
-
See usage example and API below.
-
Install the required packages:
-
NPM:
# optional (to support older browsers): npm install --save es6-promise # required (to add global `fetch` method): npm install --save isomorphic-fetch # required (this package): npm install --save frisbee
-
Bower:
# optional (to support older browsers): bower install --save es6-promise # required (to add global `fetch` method): bower install --save isomorphic-fetch # required (this package): bower install --save frisbee
-
-
Require it, set default options, and make some requests:
// add optional support for older browsers import es6promise from 'es6-promise'; es6promise.polyfill(); // add required support for global `fetch` method // *this must always come before `frisbee` is imported* import 'isomorphic-fetch'; // require the module import Frisbee from 'frisbee'; // create a new instance of Frisbee const api = new Frisbee({ baseURI: 'https://api.startup.com', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } }); makeRequests(); async function makeRequests() { // log in to our API with a user/pass try { // make the request let res = await api.post('/v1/login'); console.log('response', res.body); // 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' }); console.log('response', res.body); // 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'); console.log('response', res.body); // 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) { throw err; } }
import Frisbee from 'frisbee';
Frisbee
is a function that optionally accepts an argument options
, which is an object full of options for constructing your API instance.
-
Frisbee
- accepts anoptions
object, with the following accepted options:-
baseURI
- the default URI to use as a prefix for all HTTP requests- If your API server is running on
http://localhost:8080
, then use that as the value for this option - If you use React Native, then you most likely want to set
baseURI
as follows (e.g. making use of__DEV__
global variable):
const api = new Frisbee({ baseURI: __DEV__ ? process.env.API_BASE_URI || 'http://localhost:8080' : 'https://api.startup.com' });
- You could also set
API_BASE_URI
as an environment variable, and then set the value of this option toprocess.env.API_BASE_URI
(e.g.API_BASE_URI=http://localhost:8080 node app
) - Using React Native? You might want to read this article about automatic IP configuration.
- If your API server is running on
-
headers
- an object containing default headers to send with every request- Tip: You'll most likely want to set the
"Accept"
header to"application/json"
and the"Content-Type"
header to"application/json"
- Tip: You'll most likely want to set the
-
auth
- will call theauth()
function below and set it as a default -
arrayFormat
- how to stringify array in passed body. See qs for available formats
-
Upon being invoked, Frisbee
returns an object with the following chainable methods:
-
api.auth(creds)
- helper function that sets BasicAuth headers, and it acceptsuser
andpass
arguments- You can pass
creds
user and pass as an array, arguments, or string:([user, pass])
,(user, pass)
, or("user:pass")
, so you shouldn't have any problems! - If you don't pass both
user
andpass
arguments, then it removes any previously set BasicAuth headers from priorauth()
calls - If you pass only a
user
, then it will setpass
to an empty string''
) - If you pass
:
then it will assume you are trying to set BasicAuth headers using your ownuser:pass
string - If you pass more than two keys, then it will throw an error (since BasicAuth only consists of
user
andpass
anyways)
- You can pass
-
api.jwt(token)
- helper function that sets a JWT Bearer header. It accepts thejwt_token
as a single string argument. If you simply invoke the functionnull
as the argument for your token, it will remove JWT headers. -
All exposed HTTP methods return a Promise, and they require a
path
string, and accept an optionaloptions
object:-
Accepted method arguments:
-
path
required - the path for the HTTP request (e.g./v1/login
, will be prefixed with the value ofbaseURI
mentioned earlier) -
options
optional - an object containing options, such as header values, a request body, form data, or a querystring to send along with the request. For theGET
method (and theDELETE
method as of version1.3.0
),body
data will be encoded in the query string.Here are a few examples (you can override/merge your set default headers as well per request):
-
To set a custom header value of
X-Reply-To
on aPOST
request:const res = await api.post('/messages', { headers: { 'X-Reply-To': '7s9inuna748y4l1azchi' } });
-
-
-
List of available HTTP methods:
api.get(path, options)
- GETapi.head(path, options)
- HEAD (does not currently work - see tests)api.post(path, options)
- POSTapi.put(path, options)
- PUTapi.del(path, options)
- DELETEapi.options(path, options)
- OPTIONS (does not currently work - see tests)api.patch(path, options)
- PATCH
-
Note that you can chain the
auth
method and a HTTP method together:const res = await api.auth('foo:bar').get('/');
-
-
interceptor
- object that can be used to manipulate request and response interceptors. It has the following methods:api.interceptor.register(interceptor)
: Accepts an interceptor object that can have one or more of the following functions
{ request: function (path, options) { // Read/Modify the path or options // ... return [path, options]; }, requestError: function (err) { // Handle an error occured in the request method // ... return Promise.reject(err); }, response: function (response) { // Read/Modify the response // ... return response; }, responseError: function (err) { // Handle error occured in api/response methods return Promise.reject(err); }
the
register
method returns anunregister()
function so that you can unregister the added interceptor.-
api.interceptor.unregister(interceptor)
: Accepts the interceptor reference that you want to delete. -
api.interceptor.clear()
: Removes all the added interceptors. -
Note that when interceptors are added in the order ONE->TWO->THREE:
- The
request
/requestError
functions will run in the same orderONE->TWO->THREE
. - The
response
/responseError
functions will run in reversed orderTHREE->TWO->ONE
.
- The
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:
- https://fetch.spec.whatwg.org/
- https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
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 CrocodileJS 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.
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.
- Fork/clone this repository
- Run
npm install
- Run
npm run watch
to watch thesrc
directory for changes - Make changes in
src
directory - Write unit tests in
/test/
if you add more stuff - Run
npm test
when you're done - Submit a pull request
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:
- JakeChampion/fetch#235
- facebook/react-native#4376
- ladjs/superagent#636
- facebook/react-native#863
- facebook/react-native#370
- facebook/react-native#10
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.
- Nick Baugh niftylettuce@gmail.com
- Thanks to James Ide for coining the name "Frisbee" (it used to be called
fetch-api
, andfrisbee
was surprisingly available on NPM) - Inspiration from https://gist.github.com/anthonator/0dc0310a931398490fab, superagent, and from writing dozens of API wrappers!
- Google for being an awesome search engine to help me discover stuff on GitHub (haha)