1 | # axios
|
2 |
|
3 | [![npm version](https://img.shields.io/npm/v/axios.svg?style=flat-square)](https://www.npmjs.org/package/axios)
|
4 | [![build status](https://img.shields.io/travis/axios/axios.svg?style=flat-square)](https://travis-ci.org/axios/axios)
|
5 | [![code coverage](https://img.shields.io/coveralls/mzabriskie/axios.svg?style=flat-square)](https://coveralls.io/r/mzabriskie/axios)
|
6 | [![npm downloads](https://img.shields.io/npm/dm/axios.svg?style=flat-square)](http://npm-stat.com/charts.html?package=axios)
|
7 | [![gitter chat](https://img.shields.io/gitter/room/mzabriskie/axios.svg?style=flat-square)](https://gitter.im/mzabriskie/axios)
|
8 |
|
9 | Promise based HTTP client for the browser and node.js
|
10 |
|
11 | ## Features
|
12 |
|
13 | - Make [XMLHttpRequests](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) from the browser
|
14 | - Make [http](http://nodejs.org/api/http.html) requests from node.js
|
15 | - Supports the [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) API
|
16 | - Intercept request and response
|
17 | - Transform request and response data
|
18 | - Cancel requests
|
19 | - Automatic transforms for JSON data
|
20 | - Client side support for protecting against [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
|
21 |
|
22 | ## Browser Support
|
23 |
|
24 | ![Chrome](https://raw.github.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/src/safari/safari_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/src/opera/opera_48x48.png) | ![Edge](https://raw.github.com/alrra/browser-logos/master/src/edge/edge_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png) |
|
25 | --- | --- | --- | --- | --- | --- |
|
26 | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | 8+ ✔ |
|
27 |
|
28 | [![Browser Matrix](https://saucelabs.com/open_sauce/build_matrix/axios.svg)](https://saucelabs.com/u/axios)
|
29 |
|
30 | ## Installing
|
31 |
|
32 | Using npm:
|
33 |
|
34 | ```bash
|
35 | $ npm install axios
|
36 | ```
|
37 |
|
38 | Using bower:
|
39 |
|
40 | ```bash
|
41 | $ bower install axios
|
42 | ```
|
43 |
|
44 | Using cdn:
|
45 |
|
46 | ```html
|
47 | <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
48 | ```
|
49 |
|
50 | ## Example
|
51 |
|
52 | Performing a `GET` request
|
53 |
|
54 | ```js
|
55 | // Make a request for a user with a given ID
|
56 | axios.get('/user?ID=12345')
|
57 | .then(function (response) {
|
58 | console.log(response);
|
59 | })
|
60 | .catch(function (error) {
|
61 | console.log(error);
|
62 | });
|
63 |
|
64 | // Optionally the request above could also be done as
|
65 | axios.get('/user', {
|
66 | params: {
|
67 | ID: 12345
|
68 | }
|
69 | })
|
70 | .then(function (response) {
|
71 | console.log(response);
|
72 | })
|
73 | .catch(function (error) {
|
74 | console.log(error);
|
75 | });
|
76 | ```
|
77 |
|
78 | Performing a `POST` request
|
79 |
|
80 | ```js
|
81 | axios.post('/user', {
|
82 | firstName: 'Fred',
|
83 | lastName: 'Flintstone'
|
84 | })
|
85 | .then(function (response) {
|
86 | console.log(response);
|
87 | })
|
88 | .catch(function (error) {
|
89 | console.log(error);
|
90 | });
|
91 | ```
|
92 |
|
93 | Performing multiple concurrent requests
|
94 |
|
95 | ```js
|
96 | function getUserAccount() {
|
97 | return axios.get('/user/12345');
|
98 | }
|
99 |
|
100 | function getUserPermissions() {
|
101 | return axios.get('/user/12345/permissions');
|
102 | }
|
103 |
|
104 | axios.all([getUserAccount(), getUserPermissions()])
|
105 | .then(axios.spread(function (acct, perms) {
|
106 | // Both requests are now complete
|
107 | }));
|
108 | ```
|
109 |
|
110 | ## axios API
|
111 |
|
112 | Requests can be made by passing the relevant config to `axios`.
|
113 |
|
114 | ##### axios(config)
|
115 |
|
116 | ```js
|
117 | // Send a POST request
|
118 | axios({
|
119 | method: 'post',
|
120 | url: '/user/12345',
|
121 | data: {
|
122 | firstName: 'Fred',
|
123 | lastName: 'Flintstone'
|
124 | }
|
125 | });
|
126 | ```
|
127 |
|
128 | ```js
|
129 | // GET request for remote image
|
130 | axios({
|
131 | method:'get',
|
132 | url:'http://bit.ly/2mTM3nY',
|
133 | responseType:'stream'
|
134 | })
|
135 | .then(function(response) {
|
136 | response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
|
137 | });
|
138 | ```
|
139 |
|
140 | ##### axios(url[, config])
|
141 |
|
142 | ```js
|
143 | // Send a GET request (default method)
|
144 | axios('/user/12345');
|
145 | ```
|
146 |
|
147 | ### Request method aliases
|
148 |
|
149 | For convenience aliases have been provided for all supported request methods.
|
150 |
|
151 | ##### axios.request(config)
|
152 | ##### axios.get(url[, config])
|
153 | ##### axios.delete(url[, config])
|
154 | ##### axios.head(url[, config])
|
155 | ##### axios.options(url[, config])
|
156 | ##### axios.post(url[, data[, config]])
|
157 | ##### axios.put(url[, data[, config]])
|
158 | ##### axios.patch(url[, data[, config]])
|
159 |
|
160 | ###### NOTE
|
161 | When using the alias methods `url`, `method`, and `data` properties don't need to be specified in config.
|
162 |
|
163 | ### Concurrency
|
164 |
|
165 | Helper functions for dealing with concurrent requests.
|
166 |
|
167 | ##### axios.all(iterable)
|
168 | ##### axios.spread(callback)
|
169 |
|
170 | ### Creating an instance
|
171 |
|
172 | You can create a new instance of axios with a custom config.
|
173 |
|
174 | ##### axios.create([config])
|
175 |
|
176 | ```js
|
177 | var instance = axios.create({
|
178 | baseURL: 'https://some-domain.com/api/',
|
179 | timeout: 1000,
|
180 | headers: {'X-Custom-Header': 'foobar'}
|
181 | });
|
182 | ```
|
183 |
|
184 | ### Instance methods
|
185 |
|
186 | The available instance methods are listed below. The specified config will be merged with the instance config.
|
187 |
|
188 | ##### axios#request(config)
|
189 | ##### axios#get(url[, config])
|
190 | ##### axios#delete(url[, config])
|
191 | ##### axios#head(url[, config])
|
192 | ##### axios#options(url[, config])
|
193 | ##### axios#post(url[, data[, config]])
|
194 | ##### axios#put(url[, data[, config]])
|
195 | ##### axios#patch(url[, data[, config]])
|
196 |
|
197 | ## Request Config
|
198 |
|
199 | These are the available config options for making requests. Only the `url` is required. Requests will default to `GET` if `method` is not specified.
|
200 |
|
201 | ```js
|
202 | {
|
203 | // `url` is the server URL that will be used for the request
|
204 | url: '/user',
|
205 |
|
206 | // `method` is the request method to be used when making the request
|
207 | method: 'get', // default
|
208 |
|
209 | // `baseURL` will be prepended to `url` unless `url` is absolute.
|
210 | // It can be convenient to set `baseURL` for an instance of axios to pass relative URLs
|
211 | // to methods of that instance.
|
212 | baseURL: 'https://some-domain.com/api/',
|
213 |
|
214 | // `transformRequest` allows changes to the request data before it is sent to the server
|
215 | // This is only applicable for request methods 'PUT', 'POST', and 'PATCH'
|
216 | // The last function in the array must return a string or an instance of Buffer, ArrayBuffer,
|
217 | // FormData or Stream
|
218 | // You may modify the headers object.
|
219 | transformRequest: [function (data, headers) {
|
220 | // Do whatever you want to transform the data
|
221 |
|
222 | return data;
|
223 | }],
|
224 |
|
225 | // `transformResponse` allows changes to the response data to be made before
|
226 | // it is passed to then/catch
|
227 | transformResponse: [function (data) {
|
228 | // Do whatever you want to transform the data
|
229 |
|
230 | return data;
|
231 | }],
|
232 |
|
233 | // `headers` are custom headers to be sent
|
234 | headers: {'X-Requested-With': 'XMLHttpRequest'},
|
235 |
|
236 | // `params` are the URL parameters to be sent with the request
|
237 | // Must be a plain object or a URLSearchParams object
|
238 | params: {
|
239 | ID: 12345
|
240 | },
|
241 |
|
242 | // `paramsSerializer` is an optional function in charge of serializing `params`
|
243 | // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
|
244 | paramsSerializer: function(params) {
|
245 | return Qs.stringify(params, {arrayFormat: 'brackets'})
|
246 | },
|
247 |
|
248 | // `data` is the data to be sent as the request body
|
249 | // Only applicable for request methods 'PUT', 'POST', and 'PATCH'
|
250 | // When no `transformRequest` is set, must be of one of the following types:
|
251 | // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
|
252 | // - Browser only: FormData, File, Blob
|
253 | // - Node only: Stream, Buffer
|
254 | data: {
|
255 | firstName: 'Fred'
|
256 | },
|
257 |
|
258 | // `timeout` specifies the number of milliseconds before the request times out.
|
259 | // If the request takes longer than `timeout`, the request will be aborted.
|
260 | timeout: 1000,
|
261 |
|
262 | // `withCredentials` indicates whether or not cross-site Access-Control requests
|
263 | // should be made using credentials
|
264 | withCredentials: false, // default
|
265 |
|
266 | // `adapter` allows custom handling of requests which makes testing easier.
|
267 | // Return a promise and supply a valid response (see lib/adapters/README.md).
|
268 | adapter: function (config) {
|
269 | /* ... */
|
270 | },
|
271 |
|
272 | // `auth` indicates that HTTP Basic auth should be used, and supplies credentials.
|
273 | // This will set an `Authorization` header, overwriting any existing
|
274 | // `Authorization` custom headers you have set using `headers`.
|
275 | auth: {
|
276 | username: 'janedoe',
|
277 | password: 's00pers3cret'
|
278 | },
|
279 |
|
280 | // `responseType` indicates the type of data that the server will respond with
|
281 | // options are 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
|
282 | responseType: 'json', // default
|
283 |
|
284 | // `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
|
285 | xsrfCookieName: 'XSRF-TOKEN', // default
|
286 |
|
287 | // `xsrfHeaderName` is the name of the http header that carries the xsrf token value
|
288 | xsrfHeaderName: 'X-XSRF-TOKEN', // default
|
289 |
|
290 | // `onUploadProgress` allows handling of progress events for uploads
|
291 | onUploadProgress: function (progressEvent) {
|
292 | // Do whatever you want with the native progress event
|
293 | },
|
294 |
|
295 | // `onDownloadProgress` allows handling of progress events for downloads
|
296 | onDownloadProgress: function (progressEvent) {
|
297 | // Do whatever you want with the native progress event
|
298 | },
|
299 |
|
300 | // `maxContentLength` defines the max size of the http response content allowed
|
301 | maxContentLength: 2000,
|
302 |
|
303 | // `validateStatus` defines whether to resolve or reject the promise for a given
|
304 | // HTTP response status code. If `validateStatus` returns `true` (or is set to `null`
|
305 | // or `undefined`), the promise will be resolved; otherwise, the promise will be
|
306 | // rejected.
|
307 | validateStatus: function (status) {
|
308 | return status >= 200 && status < 300; // default
|
309 | },
|
310 |
|
311 | // `maxRedirects` defines the maximum number of redirects to follow in node.js.
|
312 | // If set to 0, no redirects will be followed.
|
313 | maxRedirects: 5, // default
|
314 |
|
315 | // `httpAgent` and `httpsAgent` define a custom agent to be used when performing http
|
316 | // and https requests, respectively, in node.js. This allows options to be added like
|
317 | // `keepAlive` that are not enabled by default.
|
318 | httpAgent: new http.Agent({ keepAlive: true }),
|
319 | httpsAgent: new https.Agent({ keepAlive: true }),
|
320 |
|
321 | // 'proxy' defines the hostname and port of the proxy server
|
322 | // Use `false` to disable proxies, ignoring environment variables.
|
323 | // `auth` indicates that HTTP Basic auth should be used to connect to the proxy, and
|
324 | // supplies credentials.
|
325 | // This will set an `Proxy-Authorization` header, overwriting any existing
|
326 | // `Proxy-Authorization` custom headers you have set using `headers`.
|
327 | proxy: {
|
328 | host: '127.0.0.1',
|
329 | port: 9000,
|
330 | auth: {
|
331 | username: 'mikeymike',
|
332 | password: 'rapunz3l'
|
333 | }
|
334 | },
|
335 |
|
336 | // `cancelToken` specifies a cancel token that can be used to cancel the request
|
337 | // (see Cancellation section below for details)
|
338 | cancelToken: new CancelToken(function (cancel) {
|
339 | })
|
340 | }
|
341 | ```
|
342 |
|
343 | ## Response Schema
|
344 |
|
345 | The response for a request contains the following information.
|
346 |
|
347 | ```js
|
348 | {
|
349 | // `data` is the response that was provided by the server
|
350 | data: {},
|
351 |
|
352 | // `status` is the HTTP status code from the server response
|
353 | status: 200,
|
354 |
|
355 | // `statusText` is the HTTP status message from the server response
|
356 | statusText: 'OK',
|
357 |
|
358 | // `headers` the headers that the server responded with
|
359 | // All header names are lower cased
|
360 | headers: {},
|
361 |
|
362 | // `config` is the config that was provided to `axios` for the request
|
363 | config: {},
|
364 |
|
365 | // `request` is the request that generated this response
|
366 | // It is the last ClientRequest instance in node.js (in redirects)
|
367 | // and an XMLHttpRequest instance the browser
|
368 | request: {}
|
369 | }
|
370 | ```
|
371 |
|
372 | When using `then`, you will receive the response as follows:
|
373 |
|
374 | ```js
|
375 | axios.get('/user/12345')
|
376 | .then(function(response) {
|
377 | console.log(response.data);
|
378 | console.log(response.status);
|
379 | console.log(response.statusText);
|
380 | console.log(response.headers);
|
381 | console.log(response.config);
|
382 | });
|
383 | ```
|
384 |
|
385 | When using `catch`, or passing a [rejection callback](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then) as second parameter of `then`, the response will be available through the `error` object as explained in the [Handling Errors](#handling-errors) section.
|
386 |
|
387 | ## Config Defaults
|
388 |
|
389 | You can specify config defaults that will be applied to every request.
|
390 |
|
391 | ### Global axios defaults
|
392 |
|
393 | ```js
|
394 | axios.defaults.baseURL = 'https://api.example.com';
|
395 | axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
|
396 | axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
|
397 | ```
|
398 |
|
399 | ### Custom instance defaults
|
400 |
|
401 | ```js
|
402 | // Set config defaults when creating the instance
|
403 | var instance = axios.create({
|
404 | baseURL: 'https://api.example.com'
|
405 | });
|
406 |
|
407 | // Alter defaults after instance has been created
|
408 | instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
|
409 | ```
|
410 |
|
411 | ### Config order of precedence
|
412 |
|
413 | Config will be merged with an order of precedence. The order is library defaults found in `lib/defaults.js`, then `defaults` property of the instance, and finally `config` argument for the request. The latter will take precedence over the former. Here's an example.
|
414 |
|
415 | ```js
|
416 | // Create an instance using the config defaults provided by the library
|
417 | // At this point the timeout config value is `0` as is the default for the library
|
418 | var instance = axios.create();
|
419 |
|
420 | // Override timeout default for the library
|
421 | // Now all requests will wait 2.5 seconds before timing out
|
422 | instance.defaults.timeout = 2500;
|
423 |
|
424 | // Override timeout for this request as it's known to take a long time
|
425 | instance.get('/longRequest', {
|
426 | timeout: 5000
|
427 | });
|
428 | ```
|
429 |
|
430 | ## Interceptors
|
431 |
|
432 | You can intercept requests or responses before they are handled by `then` or `catch`.
|
433 |
|
434 | ```js
|
435 | // Add a request interceptor
|
436 | axios.interceptors.request.use(function (config) {
|
437 | // Do something before request is sent
|
438 | return config;
|
439 | }, function (error) {
|
440 | // Do something with request error
|
441 | return Promise.reject(error);
|
442 | });
|
443 |
|
444 | // Add a response interceptor
|
445 | axios.interceptors.response.use(function (response) {
|
446 | // Do something with response data
|
447 | return response;
|
448 | }, function (error) {
|
449 | // Do something with response error
|
450 | return Promise.reject(error);
|
451 | });
|
452 | ```
|
453 |
|
454 | If you may need to remove an interceptor later you can.
|
455 |
|
456 | ```js
|
457 | var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
|
458 | axios.interceptors.request.eject(myInterceptor);
|
459 | ```
|
460 |
|
461 | You can add interceptors to a custom instance of axios.
|
462 |
|
463 | ```js
|
464 | var instance = axios.create();
|
465 | instance.interceptors.request.use(function () {/*...*/});
|
466 | ```
|
467 |
|
468 | ## Handling Errors
|
469 |
|
470 | ```js
|
471 | axios.get('/user/12345')
|
472 | .catch(function (error) {
|
473 | if (error.response) {
|
474 | // The request was made and the server responded with a status code
|
475 | // that falls out of the range of 2xx
|
476 | console.log(error.response.data);
|
477 | console.log(error.response.status);
|
478 | console.log(error.response.headers);
|
479 | } else if (error.request) {
|
480 | // The request was made but no response was received
|
481 | // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
|
482 | // http.ClientRequest in node.js
|
483 | console.log(error.request);
|
484 | } else {
|
485 | // Something happened in setting up the request that triggered an Error
|
486 | console.log('Error', error.message);
|
487 | }
|
488 | console.log(error.config);
|
489 | });
|
490 | ```
|
491 |
|
492 | You can define a custom HTTP status code error range using the `validateStatus` config option.
|
493 |
|
494 | ```js
|
495 | axios.get('/user/12345', {
|
496 | validateStatus: function (status) {
|
497 | return status < 500; // Reject only if the status code is greater than or equal to 500
|
498 | }
|
499 | })
|
500 | ```
|
501 |
|
502 | ## Cancellation
|
503 |
|
504 | You can cancel a request using a *cancel token*.
|
505 |
|
506 | > The axios cancel token API is based on the withdrawn [cancelable promises proposal](https://github.com/tc39/proposal-cancelable-promises).
|
507 |
|
508 | You can create a cancel token using the `CancelToken.source` factory as shown below:
|
509 |
|
510 | ```js
|
511 | var CancelToken = axios.CancelToken;
|
512 | var source = CancelToken.source();
|
513 |
|
514 | axios.get('/user/12345', {
|
515 | cancelToken: source.token
|
516 | }).catch(function(thrown) {
|
517 | if (axios.isCancel(thrown)) {
|
518 | console.log('Request canceled', thrown.message);
|
519 | } else {
|
520 | // handle error
|
521 | }
|
522 | });
|
523 |
|
524 | // cancel the request (the message parameter is optional)
|
525 | source.cancel('Operation canceled by the user.');
|
526 | ```
|
527 |
|
528 | You can also create a cancel token by passing an executor function to the `CancelToken` constructor:
|
529 |
|
530 | ```js
|
531 | var CancelToken = axios.CancelToken;
|
532 | var cancel;
|
533 |
|
534 | axios.get('/user/12345', {
|
535 | cancelToken: new CancelToken(function executor(c) {
|
536 | // An executor function receives a cancel function as a parameter
|
537 | cancel = c;
|
538 | })
|
539 | });
|
540 |
|
541 | // cancel the request
|
542 | cancel();
|
543 | ```
|
544 |
|
545 | > Note: you can cancel several requests with the same cancel token.
|
546 |
|
547 | ## Using application/x-www-form-urlencoded format
|
548 |
|
549 | By default, axios serializes JavaScript objects to `JSON`. To send data in the `application/x-www-form-urlencoded` format instead, you can use one of the following options.
|
550 |
|
551 | ### Browser
|
552 |
|
553 | In a browser, you can use the [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) API as follows:
|
554 |
|
555 | ```js
|
556 | var params = new URLSearchParams();
|
557 | params.append('param1', 'value1');
|
558 | params.append('param2', 'value2');
|
559 | axios.post('/foo', params);
|
560 | ```
|
561 |
|
562 | > Note that `URLSearchParams` is not supported by all browsers (see [caniuse.com](http://www.caniuse.com/#feat=urlsearchparams)), but there is a [polyfill](https://github.com/WebReflection/url-search-params) available (make sure to polyfill the global environment).
|
563 |
|
564 | Alternatively, you can encode data using the [`qs`](https://github.com/ljharb/qs) library:
|
565 |
|
566 | ```js
|
567 | var qs = require('qs');
|
568 | axios.post('/foo', qs.stringify({ 'bar': 123 }));
|
569 | ```
|
570 |
|
571 | ### Node.js
|
572 |
|
573 | In node.js, you can use the [`querystring`](https://nodejs.org/api/querystring.html) module as follows:
|
574 |
|
575 | ```js
|
576 | var querystring = require('querystring');
|
577 | axios.post('http://something.com/', querystring.stringify({ foo: 'bar' }));
|
578 | ```
|
579 |
|
580 | You can also use the [`qs`](https://github.com/ljharb/qs) library.
|
581 |
|
582 | ## Semver
|
583 |
|
584 | Until axios reaches a `1.0` release, breaking changes will be released with a new minor version. For example `0.5.1`, and `0.5.4` will have the same API, but `0.6.0` will have breaking changes.
|
585 |
|
586 | ## Promises
|
587 |
|
588 | axios depends on a native ES6 Promise implementation to be [supported](http://caniuse.com/promises).
|
589 | If your environment doesn't support ES6 Promises, you can [polyfill](https://github.com/jakearchibald/es6-promise).
|
590 |
|
591 | ## TypeScript
|
592 | axios includes [TypeScript](http://typescriptlang.org) definitions.
|
593 | ```typescript
|
594 | import axios from 'axios';
|
595 | axios.get('/user?ID=12345');
|
596 | ```
|
597 |
|
598 | ## Resources
|
599 |
|
600 | * [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
|
601 | * [Upgrade Guide](https://github.com/axios/axios/blob/master/UPGRADE_GUIDE.md)
|
602 | * [Ecosystem](https://github.com/axios/axios/blob/master/ECOSYSTEM.md)
|
603 | * [Contributing Guide](https://github.com/axios/axios/blob/master/CONTRIBUTING.md)
|
604 | * [Code of Conduct](https://github.com/axios/axios/blob/master/CODE_OF_CONDUCT.md)
|
605 |
|
606 | ## Credits
|
607 |
|
608 | axios is heavily inspired by the [$http service](https://docs.angularjs.org/api/ng/service/$http) provided in [Angular](https://angularjs.org/). Ultimately axios is an effort to provide a standalone `$http`-like service for use outside of Angular.
|
609 |
|
610 | ## License
|
611 |
|
612 | MIT
|