1 | <p align="center">
|
2 | <img src="https://i.imgur.com/0cSIPzP.png" width="300" height="300" alt="unfetch">
|
3 | <br>
|
4 | <a href="https://www.npmjs.org/package/unfetch"><img src="https://img.shields.io/npm/v/unfetch.svg?style=flat" alt="npm"></a>
|
5 | <a href="https://unpkg.com/unfetch/polyfill"><img src="https://img.badgesize.io/https://unpkg.com/unfetch/polyfill/index.js?compression=gzip" alt="gzip size"></a>
|
6 | <a href="https://www.npmjs.com/package/unfetch"><img src="https://img.shields.io/npm/dt/unfetch.svg" alt="downloads" ></a>
|
7 | <a href="https://travis-ci.org/developit/unfetch"><img src="https://travis-ci.org/developit/unfetch.svg?branch=master" alt="travis"></a>
|
8 | </p>
|
9 |
|
10 | # unfetch
|
11 |
|
12 | > Tiny 500b fetch "barely-polyfill"
|
13 |
|
14 | - **Tiny:** about **500 bytes** of [ES3](https://unpkg.com/unfetch) gzipped
|
15 | - **Minimal:** just `fetch()` with headers and text/json responses
|
16 | - **Familiar:** a subset of the full API
|
17 | - **Supported:** supports IE8+ _(assuming `Promise` is polyfilled of course!)_
|
18 | - **Standalone:** one function, no dependencies
|
19 | - **Modern:** written in ES2015, transpiled to 500b of old-school JS
|
20 |
|
21 | > 🤔 **What's Missing?**
|
22 | >
|
23 | > - Uses simple Arrays instead of Iterables, since Arrays _are_ iterables
|
24 | > - No streaming, just Promisifies existing XMLHttpRequest response bodies
|
25 | > - Use in Node.JS is handled by [isomorphic-unfetch](https://github.com/developit/unfetch/tree/master/packages/isomorphic-unfetch)
|
26 |
|
27 | * * *
|
28 |
|
29 | - [Unfetch](#unfetch)
|
30 | - [Installation](#installation)
|
31 | - [Usage: As a Polyfill](#usage-as-a-polyfill)
|
32 | - [Usage: As a Ponyfill](#usage-as-a-ponyfill)
|
33 | - [Examples & Demos](#examples--demos)
|
34 | - [API](#api)
|
35 | - [Caveats](#caveats)
|
36 | - [Contribute](#contribute)
|
37 | - [License](#license)
|
38 |
|
39 | * * *
|
40 |
|
41 | ## Installation
|
42 |
|
43 | For use with [node](http://nodejs.org) and [npm](https://npmjs.com):
|
44 |
|
45 | ```sh
|
46 | npm install --save unfetch
|
47 | ```
|
48 |
|
49 | Otherwise, grab it from [unpkg.com/unfetch](https://unpkg.com/unfetch/).
|
50 |
|
51 | * * *
|
52 |
|
53 | ## Usage: As a [Polyfill](https://ponyfill.com/#polyfill)
|
54 |
|
55 | This automatically "installs" unfetch as `window.fetch()` if it detects Fetch isn't supported:
|
56 |
|
57 | ```js
|
58 | import 'unfetch/polyfill'
|
59 |
|
60 | // fetch is now available globally!
|
61 | fetch('/foo.json')
|
62 | .then( r => r.json() )
|
63 | .then( data => console.log(data) )
|
64 | ```
|
65 |
|
66 | This polyfill version is particularly useful for hotlinking from [unpkg](https://unpkg.com):
|
67 |
|
68 | ```html
|
69 | <script src="https://unpkg.com/unfetch/polyfill"></script>
|
70 | <script>
|
71 | // now our page can use fetch!
|
72 | fetch('/foo')
|
73 | </script>
|
74 | ```
|
75 |
|
76 | * * *
|
77 |
|
78 | ## Usage: As a [Ponyfill](https://github.com/sindresorhus/ponyfill)
|
79 |
|
80 | With a module bundler like [rollup](http://rollupjs.org) or [webpack](https://webpack.js.org),
|
81 | you can import unfetch to use in your code without modifying any globals:
|
82 |
|
83 | ```js
|
84 | // using JS Modules:
|
85 | import fetch from 'unfetch'
|
86 |
|
87 | // or using CommonJS:
|
88 | var fetch = require('unfetch')
|
89 |
|
90 | // usage:
|
91 | fetch('/foo.json')
|
92 | .then( r => r.json() )
|
93 | .then( data => console.log(data) )
|
94 | ```
|
95 |
|
96 | The above will always return `unfetch()`. _(even if `window.fetch` exists!)_
|
97 |
|
98 | There's also a UMD bundle available as [unfetch/dist/unfetch.umd.js](https://unpkg.com/unfetch/dist/unfetch.umd.js), which doesn't automatically install itself as `window.fetch`.
|
99 |
|
100 | * * *
|
101 |
|
102 | ## Examples & Demos
|
103 |
|
104 | [**Real Example on JSFiddle**](https://jsfiddle.net/developit/qrh7tLc0/) ➡️
|
105 |
|
106 | ```js
|
107 | // simple GET request:
|
108 | fetch('/foo')
|
109 | .then( r => r.text() )
|
110 | .then( txt => console.log(txt) )
|
111 |
|
112 |
|
113 | // complex POST request with JSON, headers:
|
114 | fetch('/bear', {
|
115 | method: 'POST',
|
116 | headers: {
|
117 | 'Content-Type': 'application/json'
|
118 | },
|
119 | body: JSON.stringify({ hungry: true })
|
120 | }).then( r => {
|
121 | open(r.headers.get('location'));
|
122 | return r.json();
|
123 | })
|
124 | ```
|
125 |
|
126 | * * *
|
127 |
|
128 | ## API
|
129 | While one of Unfetch's goals is to provide a familiar interface, its API may differ from other `fetch` polyfills/ponyfills.
|
130 | One of the key differences is that Unfetch focuses on implementing the [`fetch()` API](https://fetch.spec.whatwg.org/#fetch-api), while offering minimal (yet functional) support to the other sections of the [Fetch spec](https://fetch.spec.whatwg.org/), like the [Headers class](https://fetch.spec.whatwg.org/#headers-class) or the [Response class](https://fetch.spec.whatwg.org/#response-class).
|
131 | Unfetch's API is organized as follows:
|
132 |
|
133 | ### `fetch(url: string, options: Object)`
|
134 | This function is the heart of Unfetch. It will fetch resources from `url` according to the given `options`, returning a Promise that will eventually resolve to the response.
|
135 |
|
136 | Unfetch will account for the following properties in `options`:
|
137 |
|
138 | * `method`: Indicates the request method to be performed on the
|
139 | target resource (The most common ones being `GET`, `POST`, `PUT`, `PATCH`, `HEAD`, `OPTIONS` or `DELETE`).
|
140 | * `headers`: An `Object` containing additional information to be sent with the request, e.g. `{ 'Content-Type': 'application/json' }` to indicate a JSON-typed request body.
|
141 | * `credentials`: ⚠ Accepts a `"include"` string, which will allow both CORS and same origin requests to work with cookies. As pointed in the ['Caveats' section](#caveats), Unfetch won't send or receive cookies otherwise. The `"same-origin"` value is not supported. ⚠
|
142 | * `body`: The content to be transmitted in request's body. Common content types include `FormData`, `JSON`, `Blob`, `ArrayBuffer` or plain text.
|
143 |
|
144 | ### `response` Methods and Attributes
|
145 | These methods are used to handle the response accordingly in your Promise chain. Instead of implementing full spec-compliant [Response Class](https://fetch.spec.whatwg.org/#response-class) functionality, Unfetch provides the following methods and attributes:
|
146 |
|
147 | #### `response.ok`
|
148 | Returns `true` if the request received a status in the `OK` range (200-299).
|
149 |
|
150 | #### `response.status`
|
151 | Contains the status code of the response, e.g. `404` for a not found resource, `200` for a success.
|
152 |
|
153 | #### `response.statusText`
|
154 | A message related to the `status` attribute, e.g. `OK` for a status `200`.
|
155 |
|
156 | #### `response.clone()`
|
157 | Will return another `Object` with the same shape and content as `response`.
|
158 |
|
159 | #### `response.text()`, `response.json()`, `response.blob()`
|
160 | Will return the response content as plain text, JSON and `Blob`, respectively.
|
161 |
|
162 | #### `response.headers`
|
163 | Again, Unfetch doesn't implement a full spec-compliant [`Headers Class`](https://fetch.spec.whatwg.org/#headers), emulating some of the Map-like functionality through its own functions:
|
164 | * `headers.keys`: Returns an `Array` containing the `key` for every header in the response.
|
165 | * `headers.entries`: Returns an `Array` containing the `[key, value]` pairs for every `Header` in the response.
|
166 | * `headers.get(key)`: Returns the `value` associated with the given `key`.
|
167 | * `headers.has(key)`: Returns a `boolean` asserting the existence of a `value` for the given `key` among the response headers.
|
168 |
|
169 | ## Caveats
|
170 |
|
171 | _Adapted from the GitHub fetch polyfill [**readme**](https://github.com/github/fetch#caveats)._
|
172 |
|
173 | The `fetch` specification differs from `jQuery.ajax()` in mainly two ways that
|
174 | bear keeping in mind:
|
175 |
|
176 | * By default, `fetch` **won't send or receive any cookies** from the server,
|
177 | resulting in unauthenticated requests if the site relies on maintaining a user
|
178 | session.
|
179 |
|
180 | ```javascript
|
181 | fetch('/users', {
|
182 | credentials: 'include'
|
183 | });
|
184 | ```
|
185 |
|
186 | * The Promise returned from `fetch()` **won't reject on HTTP error status**
|
187 | even if the response is an HTTP 404 or 500. Instead, it will resolve normally,
|
188 | and it will only reject on network failure or if anything prevented the
|
189 | request from completing.
|
190 |
|
191 | To have `fetch` Promise reject on HTTP error statuses, i.e. on any non-2xx
|
192 | status, define a custom response handler:
|
193 |
|
194 | ```javascript
|
195 | fetch('/users')
|
196 | .then( checkStatus )
|
197 | .then( r => r.json() )
|
198 | .then( data => {
|
199 | console.log(data);
|
200 | });
|
201 |
|
202 | function checkStatus(response) {
|
203 | if (response.ok) {
|
204 | return response;
|
205 | } else {
|
206 | var error = new Error(response.statusText);
|
207 | error.response = response;
|
208 | return Promise.reject(error);
|
209 | }
|
210 | }
|
211 | ```
|
212 |
|
213 | * * *
|
214 |
|
215 | ## Contribute
|
216 |
|
217 | First off, thanks for taking the time to contribute!
|
218 | Now, take a moment to be sure your contributions make sense to everyone else.
|
219 |
|
220 | ### Reporting Issues
|
221 |
|
222 | Found a problem? Want a new feature? First of all see if your issue or idea has [already been reported](../../issues).
|
223 | If it hasn't, just open a [new clear and descriptive issue](../../issues/new).
|
224 |
|
225 | ### Submitting pull requests
|
226 |
|
227 | Pull requests are the greatest contributions, so be sure they are focused in scope, and do avoid unrelated commits.
|
228 |
|
229 | > 💁 **Remember: size is the #1 priority.**
|
230 | >
|
231 | > Every byte counts! PR's can't be merged if they increase the output size much.
|
232 |
|
233 | - Fork it!
|
234 | - Clone your fork: `git clone https://github.com/<your-username>/unfetch`
|
235 | - Navigate to the newly cloned directory: `cd unfetch`
|
236 | - Create a new branch for the new feature: `git checkout -b my-new-feature`
|
237 | - Install the tools necessary for development: `npm install`
|
238 | - Make your changes.
|
239 | - `npm run build` to verify your change doesn't increase output size.
|
240 | - `npm test` to make sure your change doesn't break anything.
|
241 | - Commit your changes: `git commit -am 'Add some feature'`
|
242 | - Push to the branch: `git push origin my-new-feature`
|
243 | - Submit a pull request with full remarks documenting your changes.
|
244 |
|
245 | ## License
|
246 |
|
247 | [MIT License](LICENSE.md) © [Jason Miller](https://jasonformat.com/)
|