├── index.js
├── test
├── manual
│ ├── fixture.json
│ ├── cors.html
│ └── basic.html
├── specs
│ ├── basicAuth.spec.js
│ ├── utils
│ │ ├── trim.spec.js
│ │ ├── extend.spec.js
│ │ ├── merge.spec.js
│ │ ├── forEach.spec.js
│ │ └── isX.spec.js
│ ├── helpers
│ │ ├── bind.spec.js
│ │ ├── isURLSameOrigin.spec.js
│ │ ├── spread.spec.js
│ │ ├── btoa.spec.js
│ │ ├── normalizeHeaderName.spec.js
│ │ ├── isAbsoluteURL.spec.js
│ │ ├── combineURLs.spec.js
│ │ ├── cookies.spec.js
│ │ ├── parseHeaders.spec.js
│ │ └── buildURL.spec.js
│ ├── cancel
│ │ ├── isCancel.spec.js
│ │ ├── Cancel.spec.js
│ │ └── CancelToken.spec.js
│ ├── adapter.spec.js
│ ├── basicAuthWithPolyfill.spec.js
│ ├── core
│ │ ├── createError.spec.js
│ │ ├── enhanceError.spec.js
│ │ ├── transformData.spec.js
│ │ └── settle.spec.js
│ ├── promise.spec.js
│ ├── options.spec.js
│ ├── transform.spec.js
│ ├── headers.spec.js
│ ├── api.spec.js
│ ├── xsrf.spec.js
│ ├── instance.spec.js
│ ├── __helpers.js
│ ├── cancel.spec.js
│ ├── progress.spec.js
│ ├── defaults.spec.js
│ ├── interceptors.spec.js
│ └── requests.spec.js
└── typescript
│ └── axios.ts
├── lib
├── cancel
│ ├── isCancel.js
│ ├── Cancel.js
│ └── CancelToken.js
├── helpers
│ ├── bind.js
│ ├── README.md
│ ├── normalizeHeaderName.js
│ ├── combineURLs.js
│ ├── isAbsoluteURL.js
│ ├── spread.js
│ ├── deprecatedMethod.js
│ ├── btoa.js
│ ├── cookies.js
│ ├── parseHeaders.js
│ ├── buildURL.js
│ └── isURLSameOrigin.js
├── core
│ ├── README.md
│ ├── transformData.js
│ ├── enhanceError.js
│ ├── createError.js
│ ├── settle.js
│ ├── InterceptorManager.js
│ ├── Axios.js
│ └── dispatchRequest.js
├── adapters
│ ├── README.md
│ ├── xhr.js
│ └── http.js
├── axios.js
├── defaults.js
└── utils.js
├── .gitignore
├── examples
├── README.md
├── upload
│ ├── server.js
│ └── index.html
├── post
│ ├── server.js
│ └── index.html
├── get
│ ├── server.js
│ └── index.html
├── amd
│ └── index.html
├── all
│ └── index.html
├── transform-response
│ └── index.html
└── server.js
├── .npmignore
├── sandbox
├── client.js
├── server.js
└── client.html
├── .github
├── PULL_REQUEST_TEMPLATE.md
└── ISSUE_TEMPLATE.md
├── .travis.yml
├── bower.json
├── webpack.config.js
├── LICENSE
├── ECOSYSTEM.md
├── CONTRIBUTING.md
├── package.json
├── Gruntfile.js
├── COLLABORATOR_GUIDE.md
├── COOKBOOK.md
├── CODE_OF_CONDUCT.md
├── index.d.ts
├── UPGRADE_GUIDE.md
├── karma.conf.js
└── .eslintrc
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./lib/axios');
--------------------------------------------------------------------------------
/test/manual/fixture.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "axios"
3 | }
--------------------------------------------------------------------------------
/test/specs/basicAuth.spec.js:
--------------------------------------------------------------------------------
1 | describe('basicAuth without btoa polyfill', function () {
2 | setupBasicAuthTest();
3 | });
4 |
--------------------------------------------------------------------------------
/lib/cancel/isCancel.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function isCancel(value) {
4 | return !!(value && value.__CANCEL__);
5 | };
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .idea
3 | .tscache
4 | .DS_Store
5 | node_modules/
6 | typings/
7 | coverage/
8 | test/typescript/axios.js*
9 | sauce_connect.log
10 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | # axios examples
2 |
3 | To run the examples:
4 |
5 | 1. `git clone https://github.com/axios/axios.git`
6 | 2. `cd axios`
7 | 3. `npm install`
8 | 4. `grunt build`
9 | 5. `npm run examples`
10 | 6. [http://localhost:3000](http://localhost:3000)
11 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | **/.*
2 | *.iml
3 | coverage/
4 | examples/
5 | node_modules/
6 | typings/
7 | sandbox/
8 | test/
9 | bower.json
10 | CODE_OF_CONDUCT.md
11 | COLLABORATOR_GUIDE.md
12 | CONTRIBUTING.md
13 | COOKBOOK.md
14 | ECOSYSTEM.md
15 | Gruntfile.js
16 | karma.conf.js
17 | webpack.*.js
18 | sauce_connect.log
19 |
--------------------------------------------------------------------------------
/examples/upload/server.js:
--------------------------------------------------------------------------------
1 | module.exports = function (req, res) {
2 | var data = '';
3 |
4 | req.on('data', function (chunk) {
5 | data += chunk;
6 | });
7 |
8 | req.on('end', function () {
9 | console.log('File uploaded');
10 | res.writeHead(200);
11 | res.end();
12 | });
13 | };
14 |
--------------------------------------------------------------------------------
/lib/helpers/bind.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function bind(fn, thisArg) {
4 | return function wrap() {
5 | var args = new Array(arguments.length);
6 | for (var i = 0; i < args.length; i++) {
7 | args[i] = arguments[i];
8 | }
9 | return fn.apply(thisArg, args);
10 | };
11 | };
12 |
--------------------------------------------------------------------------------
/test/specs/utils/trim.spec.js:
--------------------------------------------------------------------------------
1 | var trim = require('../../../lib/utils').trim;
2 |
3 | describe('utils::trim', function () {
4 | it('should trim spaces', function () {
5 | expect(trim(' foo ')).toEqual('foo');
6 | });
7 |
8 | it('should trim tabs', function () {
9 | expect(trim('\tfoo\t')).toEqual('foo');
10 | });
11 | });
12 |
13 |
--------------------------------------------------------------------------------
/test/specs/helpers/bind.spec.js:
--------------------------------------------------------------------------------
1 | var bind = require('../../../lib/helpers/bind');
2 |
3 | describe('bind', function () {
4 | it('should bind an object to a function', function () {
5 | var o = { val: 123 };
6 | var f = bind(function (num) {
7 | return this.val * num;
8 | }, o);
9 |
10 | expect(f(2)).toEqual(246);
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/lib/core/README.md:
--------------------------------------------------------------------------------
1 | # axios // core
2 |
3 | The modules found in `core/` should be modules that are specific to the domain logic of axios. These modules would most likely not make sense to be consumed outside of the axios module, as their logic is too specific. Some examples of core modules are:
4 |
5 | - Dispatching requests
6 | - Managing interceptors
7 | - Handling config
8 |
--------------------------------------------------------------------------------
/lib/helpers/README.md:
--------------------------------------------------------------------------------
1 | # axios // helpers
2 |
3 | The modules found in `helpers/` should be generic modules that are _not_ specific to the domain logic of axios. These modules could theoretically be published to npm on their own and consumed by other modules or apps. Some examples of generic modules are things like:
4 |
5 | - Browser polyfills
6 | - Managing cookies
7 | - Parsing HTTP headers
8 |
--------------------------------------------------------------------------------
/examples/post/server.js:
--------------------------------------------------------------------------------
1 | module.exports = function (req, res) {
2 | var data = '';
3 |
4 | req.on('data', function (chunk) {
5 | data += chunk;
6 | });
7 |
8 | req.on('end', function () {
9 | console.log('POST data received');
10 | res.writeHead(200, {
11 | 'Content-Type': 'text/json'
12 | });
13 | res.write(JSON.stringify(data));
14 | res.end();
15 | });
16 | };
17 |
--------------------------------------------------------------------------------
/lib/helpers/normalizeHeaderName.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('../utils');
4 |
5 | module.exports = function normalizeHeaderName(headers, normalizedName) {
6 | utils.forEach(headers, function processHeader(value, name) {
7 | if (name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()) {
8 | headers[normalizedName] = value;
9 | delete headers[name];
10 | }
11 | });
12 | };
13 |
--------------------------------------------------------------------------------
/test/specs/cancel/isCancel.spec.js:
--------------------------------------------------------------------------------
1 | var isCancel = require('../../../lib/cancel/isCancel');
2 | var Cancel = require('../../../lib/cancel/Cancel');
3 |
4 | describe('isCancel', function() {
5 | it('returns true if value is a Cancel', function() {
6 | expect(isCancel(new Cancel())).toBe(true);
7 | });
8 |
9 | it('returns false if value is not a Cancel', function() {
10 | expect(isCancel({ foo: 'bar' })).toBe(false);
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/test/specs/adapter.spec.js:
--------------------------------------------------------------------------------
1 | var axios = require('../../index');
2 |
3 | describe('adapter', function () {
4 | it('should support custom adapter', function (done) {
5 | var called = false;
6 |
7 | axios('/foo', {
8 | adapter: function (config) {
9 | called = true;
10 | }
11 | });
12 |
13 | setTimeout(function () {
14 | expect(called).toBe(true);
15 | done();
16 | }, 100);
17 | });
18 | });
19 |
20 |
--------------------------------------------------------------------------------
/lib/helpers/combineURLs.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Creates a new URL by combining the specified URLs
5 | *
6 | * @param {string} baseURL The base URL
7 | * @param {string} relativeURL The relative URL
8 | * @returns {string} The combined URL
9 | */
10 | module.exports = function combineURLs(baseURL, relativeURL) {
11 | return relativeURL
12 | ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
13 | : baseURL;
14 | };
15 |
--------------------------------------------------------------------------------
/test/specs/helpers/isURLSameOrigin.spec.js:
--------------------------------------------------------------------------------
1 | var isURLSameOrigin = require('../../../lib/helpers/isURLSameOrigin');
2 |
3 | describe('helpers::isURLSameOrigin', function () {
4 | it('should detect same origin', function () {
5 | expect(isURLSameOrigin(window.location.href)).toEqual(true);
6 | });
7 |
8 | it('should detect different origin', function () {
9 | expect(isURLSameOrigin('https://github.com/axios/axios')).toEqual(false);
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/lib/cancel/Cancel.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * A `Cancel` is an object that is thrown when an operation is canceled.
5 | *
6 | * @class
7 | * @param {string=} message The message.
8 | */
9 | function Cancel(message) {
10 | this.message = message;
11 | }
12 |
13 | Cancel.prototype.toString = function toString() {
14 | return 'Cancel' + (this.message ? ': ' + this.message : '');
15 | };
16 |
17 | Cancel.prototype.__CANCEL__ = true;
18 |
19 | module.exports = Cancel;
20 |
--------------------------------------------------------------------------------
/sandbox/client.js:
--------------------------------------------------------------------------------
1 | var axios = require('../index');
2 |
3 | var URL = 'http://127.0.0.1:3000/api';
4 | var BODY = {
5 | foo: 'bar',
6 | baz: 1234
7 | };
8 |
9 | function handleSuccess(data) { console.log(data); }
10 | function handleFailure(data) { console.log('error', data); }
11 |
12 | // GET
13 | axios.get(URL, { params: BODY })
14 | .then(handleSuccess)
15 | .catch(handleFailure);
16 |
17 | // POST
18 | axios.post(URL, BODY)
19 | .then(handleSuccess)
20 | .catch(handleFailure);
--------------------------------------------------------------------------------
/test/specs/basicAuthWithPolyfill.spec.js:
--------------------------------------------------------------------------------
1 | var window_btoa;
2 |
3 | describe('basicAuth with btoa polyfill', function () {
4 | beforeAll(function() {
5 | window_btoa = window.btoa;
6 | window.btoa = undefined;
7 | });
8 |
9 | afterAll(function() {
10 | window.btoa = window_btoa;
11 | window_btoa = undefined;
12 | });
13 |
14 | it('should not have native window.btoa', function () {
15 | expect(window.btoa).toEqual(undefined);
16 | });
17 |
18 | setupBasicAuthTest();
19 | });
20 |
21 |
--------------------------------------------------------------------------------
/test/specs/helpers/spread.spec.js:
--------------------------------------------------------------------------------
1 | var spread = require('../../../lib/helpers/spread');
2 |
3 | describe('helpers::spread', function () {
4 | it('should spread array to arguments', function () {
5 | var value = 0;
6 | spread(function (a, b) {
7 | value = a * b;
8 | })([5, 10]);
9 |
10 | expect(value).toEqual(50);
11 | });
12 |
13 | it('should return callback result', function () {
14 | var value = spread(function (a, b) {
15 | return a * b;
16 | })([5, 10]);
17 |
18 | expect(value).toEqual(50);
19 | });
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/test/manual/cors.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | An alert should be shown with {"status":"ok"}
9 |
10 |
11 |
12 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/test/specs/cancel/Cancel.spec.js:
--------------------------------------------------------------------------------
1 | var Cancel = require('../../../lib/cancel/Cancel');
2 |
3 | describe('Cancel', function() {
4 | describe('toString', function() {
5 | it('returns correct result when message is not specified', function() {
6 | var cancel = new Cancel();
7 | expect(cancel.toString()).toBe('Cancel');
8 | });
9 |
10 | it('returns correct result when message is specified', function() {
11 | var cancel = new Cancel('Operation has been canceled.');
12 | expect(cancel.toString()).toBe('Cancel: Operation has been canceled.');
13 | });
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/test/manual/basic.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | An alert should be shown with the {"name":"axios"}
9 |
10 |
11 |
12 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/lib/helpers/isAbsoluteURL.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Determines whether the specified URL is absolute
5 | *
6 | * @param {string} url The URL to test
7 | * @returns {boolean} True if the specified URL is absolute, otherwise false
8 | */
9 | module.exports = function isAbsoluteURL(url) {
10 | // A URL is considered absolute if it begins with "://" or "//" (protocol-relative URL).
11 | // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed
12 | // by any combination of letters, digits, plus, period, or hyphen.
13 | return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url);
14 | };
15 |
--------------------------------------------------------------------------------
/lib/core/transformData.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('./../utils');
4 |
5 | /**
6 | * Transform the data for a request or a response
7 | *
8 | * @param {Object|String} data The data to be transformed
9 | * @param {Array} headers The headers for the request or response
10 | * @param {Array|Function} fns A single function or Array of functions
11 | * @returns {*} The resulting transformed data
12 | */
13 | module.exports = function transformData(data, headers, fns) {
14 | /*eslint no-param-reassign:0*/
15 | utils.forEach(fns, function transform(fn) {
16 | data = fn(data, headers);
17 | });
18 |
19 | return data;
20 | };
21 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | #### Instructions
4 |
5 | Please read and follow this instructions before creating and submitting a pull request:
6 |
7 | - Create an issue explaining the feature. It could save you some effort in case we don't consider it should be included in axios.
8 | - If you're fixing a bug, try to commit the failing test/s and the code fixing it in different commits.
9 | - Ensure you're following our [contributing guide](https://github.com/axios/axios/blob/master/CONTRIBUTING.md).
10 |
11 | *^^^ Delete the instructions before submitting the pull request ^^^*
12 |
13 | Describe your pull request here.
14 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - node
4 | email:
5 | on_failure: change
6 | on_success: never
7 | before_script:
8 | - "export DISPLAY=:99.0"
9 | - "sh -e /etc/init.d/xvfb start"
10 | - sleep 3 # give xvfb some time to start
11 | after_success:
12 | - npm run coveralls
13 | env:
14 | global:
15 | - secure: LlXIBEaBLgJznkHWfTV6aftkGoBjH2vik4ZQhKq4k5pvoPLD+n5n28+0bjwlzDIHUdHb+n2YXtyM2PGvGzuqwltV+UY1gu0uG2RNR+5CBsp0pOr0FfGXK6YMXn0BYER6tGYIhaG7ElHBEO0SLcQeQV/xN/m3leyawbKEMBUGizU=
16 | - secure: XbXYzVddHJSVdbJRd/YtsdNu6Wlgx3pXvpuBpg9qBc3TytAF4LzhJNI8u1p4D1Gn8wANlxv1GNgEgkecxbzlTPST+mUrd6KlPLa1+Cmffgajr4oQjsh9ILKMe5Haqx8FOVrPK/leB1mi52liNLlkuo3/BK2r/tC2kMji+2zbses=
17 |
--------------------------------------------------------------------------------
/lib/core/enhanceError.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Update an Error with the specified config, error code, and response.
5 | *
6 | * @param {Error} error The error to update.
7 | * @param {Object} config The config.
8 | * @param {string} [code] The error code (for example, 'ECONNABORTED').
9 | * @param {Object} [request] The request.
10 | * @param {Object} [response] The response.
11 | * @returns {Error} The error.
12 | */
13 | module.exports = function enhanceError(error, config, code, request, response) {
14 | error.config = config;
15 | if (code) {
16 | error.code = code;
17 | }
18 | error.request = request;
19 | error.response = response;
20 | return error;
21 | };
22 |
--------------------------------------------------------------------------------
/lib/helpers/spread.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Syntactic sugar for invoking a function and expanding an array for arguments.
5 | *
6 | * Common use case would be to use `Function.prototype.apply`.
7 | *
8 | * ```js
9 | * function f(x, y, z) {}
10 | * var args = [1, 2, 3];
11 | * f.apply(null, args);
12 | * ```
13 | *
14 | * With `spread` this example can be re-written.
15 | *
16 | * ```js
17 | * spread(function(x, y, z) {})([1, 2, 3]);
18 | * ```
19 | *
20 | * @param {Function} callback
21 | * @returns {Function}
22 | */
23 | module.exports = function spread(callback) {
24 | return function wrap(arr) {
25 | return callback.apply(null, arr);
26 | };
27 | };
28 |
--------------------------------------------------------------------------------
/lib/core/createError.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var enhanceError = require('./enhanceError');
4 |
5 | /**
6 | * Create an Error with the specified message, config, error code, request and response.
7 | *
8 | * @param {string} message The error message.
9 | * @param {Object} config The config.
10 | * @param {string} [code] The error code (for example, 'ECONNABORTED').
11 | * @param {Object} [request] The request.
12 | * @param {Object} [response] The response.
13 | * @returns {Error} The created error.
14 | */
15 | module.exports = function createError(message, config, code, request, response) {
16 | var error = new Error(message);
17 | return enhanceError(error, config, code, request, response);
18 | };
19 |
--------------------------------------------------------------------------------
/test/specs/core/createError.spec.js:
--------------------------------------------------------------------------------
1 | var createError = require('../../../lib/core/createError');
2 |
3 | describe('core::createError', function() {
4 | it('should create an Error with message, config, code, request and response', function() {
5 | var request = { path: '/foo' };
6 | var response = { status: 200, data: { foo: 'bar' } };
7 | var error = createError('Boom!', { foo: 'bar' }, 'ESOMETHING', request, response);
8 | expect(error instanceof Error).toBe(true);
9 | expect(error.message).toBe('Boom!');
10 | expect(error.config).toEqual({ foo: 'bar' });
11 | expect(error.code).toBe('ESOMETHING');
12 | expect(error.request).toBe(request);
13 | expect(error.response).toBe(response);
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/test/specs/helpers/btoa.spec.js:
--------------------------------------------------------------------------------
1 | var __btoa = require('../../../lib/helpers/btoa');
2 |
3 | describe('btoa polyfill', function () {
4 | it('should behave the same as native window.btoa', function () {
5 | // btoa doesn't exist in IE8/9
6 | if (isOldIE && typeof Int8Array === 'undefined') {
7 | return;
8 | }
9 |
10 | var data = 'Hello, world';
11 | expect(__btoa(data)).toEqual(window.btoa(data));
12 | });
13 |
14 | it('should throw an error if char is out of range 0xFF', function () {
15 | var err;
16 | var data = 'I ♡ Unicode!';
17 |
18 | try {
19 | __btoa(data);
20 | } catch (e) {
21 | err = e;
22 | }
23 |
24 | validateInvalidCharacterError(err);
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/examples/get/server.js:
--------------------------------------------------------------------------------
1 | var people = [
2 | {
3 | "name": "Matt Zabriskie",
4 | "github": "mzabriskie",
5 | "twitter": "mzabriskie",
6 | "avatar": "199035"
7 | },
8 | {
9 | "name": "Ryan Florence",
10 | "github": "rpflorence",
11 | "twitter": "ryanflorence",
12 | "avatar": "100200"
13 | },
14 | {
15 | "name": "Kent C. Dodds",
16 | "github": "kentcdodds",
17 | "twitter": "kentcdodds",
18 | "avatar": "1500684"
19 | },
20 | {
21 | "name": "Chris Esplin",
22 | "github": "deltaepsilon",
23 | "twitter": "chrisesplin",
24 | "avatar": "878947"
25 | }
26 | ];
27 |
28 | module.exports = function (req, res) {
29 | res.writeHead(200, {
30 | 'Content-Type': 'text/json'
31 | });
32 | res.write(JSON.stringify(people));
33 | res.end();
34 | };
35 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@contentful/axios",
3 | "main": "./dist/axios.js",
4 | "version": "0.18.0",
5 | "homepage": "https://github.com/axios/axios",
6 | "authors": [
7 | "Matt Zabriskie"
8 | ],
9 | "description": "Promise based HTTP client for the browser and node.js",
10 | "moduleType": [
11 | "amd",
12 | "globals"
13 | ],
14 | "keywords": [
15 | "xhr",
16 | "http",
17 | "ajax",
18 | "promise",
19 | "node"
20 | ],
21 | "license": "MIT",
22 | "ignore": [
23 | "**/.*",
24 | "*.iml",
25 | "examples",
26 | "lib",
27 | "node_modules",
28 | "sandbox",
29 | "test",
30 | "CONTRIBUTING.md",
31 | "COOKBOOK.md",
32 | "Gruntfile.js",
33 | "index.js",
34 | "karma.conf.js",
35 | "package.json",
36 | "webpack.*.js"
37 | ]
38 | }
--------------------------------------------------------------------------------
/test/specs/helpers/normalizeHeaderName.spec.js:
--------------------------------------------------------------------------------
1 | var normalizeHeaderName = require('../../../lib/helpers/normalizeHeaderName');
2 |
3 | describe('helpers::normalizeHeaderName', function () {
4 | it('should normalize matching header name', function () {
5 | var headers = {
6 | 'conTenT-Type': 'foo/bar',
7 | };
8 | normalizeHeaderName(headers, 'Content-Type');
9 | expect(headers['Content-Type']).toBe('foo/bar');
10 | expect(headers['conTenT-Type']).toBeUndefined();
11 | });
12 |
13 | it('should not change non-matching header name', function () {
14 | var headers = {
15 | 'content-type': 'foo/bar',
16 | };
17 | normalizeHeaderName(headers, 'Content-Length');
18 | expect(headers['content-type']).toBe('foo/bar');
19 | expect(headers['Content-Length']).toBeUndefined();
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/test/specs/core/enhanceError.spec.js:
--------------------------------------------------------------------------------
1 | var enhanceError = require('../../../lib/core/enhanceError');
2 |
3 | describe('core::enhanceError', function() {
4 | it('should add config, config, request and response to error', function() {
5 | var error = new Error('Boom!');
6 | var request = { path: '/foo' };
7 | var response = { status: 200, data: { foo: 'bar' } };
8 |
9 | enhanceError(error, { foo: 'bar' }, 'ESOMETHING', request, response);
10 | expect(error.config).toEqual({ foo: 'bar' });
11 | expect(error.code).toBe('ESOMETHING');
12 | expect(error.request).toBe(request);
13 | expect(error.response).toBe(response);
14 | });
15 |
16 | it('should return error', function() {
17 | var error = new Error('Boom!');
18 | expect(enhanceError(error, { foo: 'bar' }, 'ESOMETHING')).toBe(error);
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/test/specs/core/transformData.spec.js:
--------------------------------------------------------------------------------
1 | var transformData = require('../../../lib/core/transformData');
2 |
3 | describe('core::transformData', function () {
4 | it('should support a single transformer', function () {
5 | var data;
6 | data = transformData(data, null, function (data) {
7 | data = 'foo';
8 | return data;
9 | });
10 |
11 | expect(data).toEqual('foo');
12 | });
13 |
14 | it('should support an array of transformers', function () {
15 | var data = '';
16 | data = transformData(data, null, [function (data) {
17 | data += 'f';
18 | return data;
19 | }, function (data) {
20 | data += 'o';
21 | return data;
22 | }, function (data) {
23 | data += 'o';
24 | return data;
25 | }]);
26 |
27 | expect(data).toEqual('foo');
28 | });
29 | });
30 |
31 |
--------------------------------------------------------------------------------
/lib/helpers/deprecatedMethod.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*eslint no-console:0*/
4 |
5 | /**
6 | * Supply a warning to the developer that a method they are using
7 | * has been deprecated.
8 | *
9 | * @param {string} method The name of the deprecated method
10 | * @param {string} [instead] The alternate method to use if applicable
11 | * @param {string} [docs] The documentation URL to get further details
12 | */
13 | module.exports = function deprecatedMethod(method, instead, docs) {
14 | try {
15 | console.warn(
16 | 'DEPRECATED method `' + method + '`.' +
17 | (instead ? ' Use `' + instead + '` instead.' : '') +
18 | ' This method will be removed in a future release.');
19 |
20 | if (docs) {
21 | console.warn('For more information about usage see ' + docs);
22 | }
23 | } catch (e) { /* Ignore */ }
24 | };
25 |
--------------------------------------------------------------------------------
/lib/core/settle.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var createError = require('./createError');
4 |
5 | /**
6 | * Resolve or reject a Promise based on response status.
7 | *
8 | * @param {Function} resolve A function that resolves the promise.
9 | * @param {Function} reject A function that rejects the promise.
10 | * @param {object} response The response.
11 | */
12 | module.exports = function settle(resolve, reject, response) {
13 | var validateStatus = response.config.validateStatus;
14 | // Note: status is not exposed by XDomainRequest
15 | if (!response.status || !validateStatus || validateStatus(response.status)) {
16 | resolve(response);
17 | } else {
18 | reject(createError(
19 | 'Request failed with status code ' + response.status,
20 | response.config,
21 | null,
22 | response.request,
23 | response
24 | ));
25 | }
26 | };
27 |
--------------------------------------------------------------------------------
/test/specs/utils/extend.spec.js:
--------------------------------------------------------------------------------
1 | var extend = require('../../../lib/utils').extend;
2 |
3 | describe('utils::extend', function () {
4 | it('should be mutable', function () {
5 | var a = {};
6 | var b = {foo: 123};
7 |
8 | extend(a, b);
9 |
10 | expect(a.foo).toEqual(b.foo);
11 | });
12 |
13 | it('should extend properties', function () {
14 | var a = {foo: 123, bar: 456};
15 | var b = {bar: 789};
16 |
17 | a = extend(a, b);
18 |
19 | expect(a.foo).toEqual(123);
20 | expect(a.bar).toEqual(789);
21 | });
22 |
23 | it('should bind to thisArg', function () {
24 | var a = {};
25 | var b = {getFoo: function getFoo() { return this.foo; }};
26 | var thisArg = { foo: 'barbaz' };
27 |
28 | extend(a, b, thisArg);
29 |
30 | expect(typeof a.getFoo).toEqual('function');
31 | expect(a.getFoo()).toEqual(thisArg.foo);
32 | });
33 | });
34 |
35 |
--------------------------------------------------------------------------------
/test/specs/helpers/isAbsoluteURL.spec.js:
--------------------------------------------------------------------------------
1 | var isAbsoluteURL = require('../../../lib/helpers/isAbsoluteURL');
2 |
3 | describe('helpers::isAbsoluteURL', function () {
4 | it('should return true if URL begins with valid scheme name', function () {
5 | expect(isAbsoluteURL('https://api.github.com/users')).toBe(true);
6 | expect(isAbsoluteURL('custom-scheme-v1.0://example.com/')).toBe(true);
7 | expect(isAbsoluteURL('HTTP://example.com/')).toBe(true);
8 | });
9 |
10 | it('should return false if URL begins with invalid scheme name', function () {
11 | expect(isAbsoluteURL('123://example.com/')).toBe(false);
12 | expect(isAbsoluteURL('!valid://example.com/')).toBe(false);
13 | });
14 |
15 | it('should return true if URL is protocol-relative', function () {
16 | expect(isAbsoluteURL('//example.com/')).toBe(true);
17 | });
18 |
19 | it('should return false if URL is relative', function () {
20 | expect(isAbsoluteURL('/foo')).toBe(false);
21 | expect(isAbsoluteURL('foo')).toBe(false);
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var config = {};
3 |
4 | function generateConfig(name) {
5 | var uglify = name.indexOf('min') > -1;
6 | var config = {
7 | entry: './index.js',
8 | output: {
9 | path: 'dist/',
10 | filename: name + '.js',
11 | sourceMapFilename: name + '.map',
12 | library: 'axios',
13 | libraryTarget: 'umd'
14 | },
15 | node: {
16 | process: false
17 | },
18 | devtool: 'source-map'
19 | };
20 |
21 | config.plugins = [
22 | new webpack.DefinePlugin({
23 | 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
24 | })
25 | ];
26 |
27 | if (uglify) {
28 | config.plugins.push(
29 | new webpack.optimize.UglifyJsPlugin({
30 | compressor: {
31 | warnings: false
32 | }
33 | })
34 | );
35 | }
36 |
37 | return config;
38 | }
39 |
40 | ['axios', 'axios.min'].forEach(function (key) {
41 | config[key] = generateConfig(key);
42 | });
43 |
44 | module.exports = config;
45 |
--------------------------------------------------------------------------------
/test/specs/helpers/combineURLs.spec.js:
--------------------------------------------------------------------------------
1 | var combineURLs = require('../../../lib/helpers/combineURLs');
2 |
3 | describe('helpers::combineURLs', function () {
4 | it('should combine URLs', function () {
5 | expect(combineURLs('https://api.github.com', '/users')).toBe('https://api.github.com/users');
6 | });
7 |
8 | it('should remove duplicate slashes', function () {
9 | expect(combineURLs('https://api.github.com/', '/users')).toBe('https://api.github.com/users');
10 | });
11 |
12 | it('should insert missing slash', function () {
13 | expect(combineURLs('https://api.github.com', 'users')).toBe('https://api.github.com/users');
14 | });
15 |
16 | it('should not insert slash when relative url missing/empty', function () {
17 | expect(combineURLs('https://api.github.com/users', '')).toBe('https://api.github.com/users');
18 | });
19 |
20 | it('should allow a single slash for relative url', function () {
21 | expect(combineURLs('https://api.github.com/users', '/')).toBe('https://api.github.com/users/');
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/lib/adapters/README.md:
--------------------------------------------------------------------------------
1 | # axios // adapters
2 |
3 | The modules under `adapters/` are modules that handle dispatching a request and settling a returned `Promise` once a response is received.
4 |
5 | ## Example
6 |
7 | ```js
8 | var settle = require('./../core/settle');
9 |
10 | module.exports = function myAdapter(config) {
11 | // At this point:
12 | // - config has been merged with defaults
13 | // - request transformers have already run
14 | // - request interceptors have already run
15 |
16 | // Make the request using config provided
17 | // Upon response settle the Promise
18 |
19 | return new Promise(function(resolve, reject) {
20 |
21 | var response = {
22 | data: responseData,
23 | status: request.status,
24 | statusText: request.statusText,
25 | headers: responseHeaders,
26 | config: config,
27 | request: request
28 | };
29 |
30 | settle(resolve, reject, response);
31 |
32 | // From here:
33 | // - response transformers will run
34 | // - response interceptors will run
35 | });
36 | }
37 | ```
38 |
--------------------------------------------------------------------------------
/test/specs/utils/merge.spec.js:
--------------------------------------------------------------------------------
1 | var merge = require('../../../lib/utils').merge;
2 |
3 | describe('utils::merge', function () {
4 | it('should be immutable', function () {
5 | var a = {};
6 | var b = {foo: 123};
7 | var c = {bar: 456};
8 |
9 | merge(a, b, c);
10 |
11 | expect(typeof a.foo).toEqual('undefined');
12 | expect(typeof a.bar).toEqual('undefined');
13 | expect(typeof b.bar).toEqual('undefined');
14 | expect(typeof c.foo).toEqual('undefined');
15 | });
16 |
17 | it('should merge properties', function () {
18 | var a = {foo: 123};
19 | var b = {bar: 456};
20 | var c = {foo: 789};
21 | var d = merge(a, b, c);
22 |
23 | expect(d.foo).toEqual(789);
24 | expect(d.bar).toEqual(456);
25 | });
26 |
27 | it('should merge recursively', function () {
28 | var a = {foo: {bar: 123}};
29 | var b = {foo: {baz: 456}, bar: {qux: 789}};
30 |
31 | expect(merge(a, b)).toEqual({
32 | foo: {
33 | bar: 123,
34 | baz: 456
35 | },
36 | bar: {
37 | qux: 789
38 | }
39 | });
40 | });
41 | });
42 |
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 Matt Zabriskie
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/lib/helpers/btoa.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // btoa polyfill for IE<10 courtesy https://github.com/davidchambers/Base64.js
4 |
5 | var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
6 |
7 | function E() {
8 | this.message = 'String contains an invalid character';
9 | }
10 | E.prototype = new Error;
11 | E.prototype.code = 5;
12 | E.prototype.name = 'InvalidCharacterError';
13 |
14 | function btoa(input) {
15 | var str = String(input);
16 | var output = '';
17 | for (
18 | // initialize result and counter
19 | var block, charCode, idx = 0, map = chars;
20 | // if the next str index does not exist:
21 | // change the mapping table to "="
22 | // check if d has no fractional digits
23 | str.charAt(idx | 0) || (map = '=', idx % 1);
24 | // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
25 | output += map.charAt(63 & block >> 8 - idx % 1 * 8)
26 | ) {
27 | charCode = str.charCodeAt(idx += 3 / 4);
28 | if (charCode > 0xFF) {
29 | throw new E();
30 | }
31 | block = block << 8 | charCode;
32 | }
33 | return output;
34 | }
35 |
36 | module.exports = btoa;
37 |
--------------------------------------------------------------------------------
/examples/amd/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AMD
5 |
6 |
7 |
8 | AMD
9 |
10 |
11 |
User
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/test/specs/helpers/cookies.spec.js:
--------------------------------------------------------------------------------
1 | var cookies = require('../../../lib/helpers/cookies');
2 |
3 | describe('helpers::cookies', function () {
4 | afterEach(function () {
5 | // Remove all the cookies
6 | var expires = Date.now() - (60 * 60 * 24 * 7);
7 | document.cookie.split(';').map(function (cookie) {
8 | return cookie.split('=')[0];
9 | }).forEach(function (name) {
10 | document.cookie = name + '=; expires=' + new Date(expires).toGMTString();
11 | });
12 | });
13 |
14 | it('should write cookies', function () {
15 | cookies.write('foo', 'baz');
16 | expect(document.cookie).toEqual('foo=baz');
17 | });
18 |
19 | it('should read cookies', function () {
20 | cookies.write('foo', 'abc');
21 | cookies.write('bar', 'def');
22 | expect(cookies.read('foo')).toEqual('abc');
23 | expect(cookies.read('bar')).toEqual('def');
24 | });
25 |
26 | it('should remove cookies', function () {
27 | cookies.write('foo', 'bar');
28 | cookies.remove('foo');
29 | expect(cookies.read('foo')).toEqual(null);
30 | });
31 |
32 | it('should uri encode values', function () {
33 | cookies.write('foo', 'bar baz%');
34 | expect(document.cookie).toEqual('foo=bar%20baz%25');
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/examples/post/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | axios - post example
5 |
6 |
7 |
8 | axios.post
9 |
10 |
17 |
18 |
19 |
20 |
21 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/test/specs/utils/forEach.spec.js:
--------------------------------------------------------------------------------
1 | var forEach = require('../../../lib/utils').forEach;
2 |
3 | describe('utils::forEach', function () {
4 | it('should loop over an array', function () {
5 | var sum = 0;
6 |
7 | forEach([1, 2, 3, 4, 5], function (val) {
8 | sum += val;
9 | });
10 |
11 | expect(sum).toEqual(15);
12 | });
13 |
14 | it('should loop over object keys', function () {
15 | var keys = '';
16 | var vals = 0;
17 | var obj = {
18 | b: 1,
19 | a: 2,
20 | r: 3
21 | };
22 |
23 | forEach(obj, function (v, k) {
24 | keys += k;
25 | vals += v;
26 | });
27 |
28 | expect(keys).toEqual('bar');
29 | expect(vals).toEqual(6);
30 | });
31 |
32 | it('should handle undefined gracefully', function () {
33 | var count = 0;
34 |
35 | forEach(undefined, function () {
36 | count++;
37 | });
38 |
39 | expect(count).toEqual(0);
40 | });
41 |
42 | it('should make an array out of non-array argument', function () {
43 | var count = 0;
44 |
45 | forEach(function () {}, function () {
46 | count++;
47 | });
48 |
49 | expect(count).toEqual(1);
50 | });
51 |
52 | it('should handle non object prototype gracefully', function () {
53 | var count = 0;
54 | var data = Object.create(null);
55 | data.foo = 'bar'
56 |
57 | forEach(data, function () {
58 | count++;
59 | });
60 |
61 | expect(count).toEqual(1);
62 | });
63 | });
64 |
--------------------------------------------------------------------------------
/examples/get/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | axios - get example
5 |
6 |
7 |
8 | axios.get
9 |
10 |
11 |
12 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/lib/core/InterceptorManager.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('./../utils');
4 |
5 | function InterceptorManager() {
6 | this.handlers = [];
7 | }
8 |
9 | /**
10 | * Add a new interceptor to the stack
11 | *
12 | * @param {Function} fulfilled The function to handle `then` for a `Promise`
13 | * @param {Function} rejected The function to handle `reject` for a `Promise`
14 | *
15 | * @return {Number} An ID used to remove interceptor later
16 | */
17 | InterceptorManager.prototype.use = function use(fulfilled, rejected) {
18 | this.handlers.push({
19 | fulfilled: fulfilled,
20 | rejected: rejected
21 | });
22 | return this.handlers.length - 1;
23 | };
24 |
25 | /**
26 | * Remove an interceptor from the stack
27 | *
28 | * @param {Number} id The ID that was returned by `use`
29 | */
30 | InterceptorManager.prototype.eject = function eject(id) {
31 | if (this.handlers[id]) {
32 | this.handlers[id] = null;
33 | }
34 | };
35 |
36 | /**
37 | * Iterate over all the registered interceptors
38 | *
39 | * This method is particularly useful for skipping over any
40 | * interceptors that may have become `null` calling `eject`.
41 | *
42 | * @param {Function} fn The function to call for each interceptor
43 | */
44 | InterceptorManager.prototype.forEach = function forEach(fn) {
45 | utils.forEach(this.handlers, function forEachHandler(h) {
46 | if (h !== null) {
47 | fn(h);
48 | }
49 | });
50 | };
51 |
52 | module.exports = InterceptorManager;
53 |
--------------------------------------------------------------------------------
/lib/cancel/CancelToken.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Cancel = require('./Cancel');
4 |
5 | /**
6 | * A `CancelToken` is an object that can be used to request cancellation of an operation.
7 | *
8 | * @class
9 | * @param {Function} executor The executor function.
10 | */
11 | function CancelToken(executor) {
12 | if (typeof executor !== 'function') {
13 | throw new TypeError('executor must be a function.');
14 | }
15 |
16 | var resolvePromise;
17 | this.promise = new Promise(function promiseExecutor(resolve) {
18 | resolvePromise = resolve;
19 | });
20 |
21 | var token = this;
22 | executor(function cancel(message) {
23 | if (token.reason) {
24 | // Cancellation has already been requested
25 | return;
26 | }
27 |
28 | token.reason = new Cancel(message);
29 | resolvePromise(token.reason);
30 | });
31 | }
32 |
33 | /**
34 | * Throws a `Cancel` if cancellation has been requested.
35 | */
36 | CancelToken.prototype.throwIfRequested = function throwIfRequested() {
37 | if (this.reason) {
38 | throw this.reason;
39 | }
40 | };
41 |
42 | /**
43 | * Returns an object that contains a new `CancelToken` and a function that, when called,
44 | * cancels the `CancelToken`.
45 | */
46 | CancelToken.source = function source() {
47 | var cancel;
48 | var token = new CancelToken(function executor(c) {
49 | cancel = c;
50 | });
51 | return {
52 | token: token,
53 | cancel: cancel
54 | };
55 | };
56 |
57 | module.exports = CancelToken;
58 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | #### Instructions
4 |
5 | Please read and follow this instructions before submitting an issue:
6 |
7 | - Read all our documentation, specially the [README](https://github.com/axios/axios/blob/master/README.md). It may contain information that helps you solve your issue.
8 | - Ensure your issue isn't already [reported](https://github.com/axios/axios/issues?utf8=%E2%9C%93&q=is%3Aissue).
9 | - If you aren't sure that the issue is caused by axios or you just need for help, please use [Stack Overflow](https://stackoverflow.com/questions/tagged/axios) or [our chat](https://gitter.im/mzabriskie/axios).
10 | - If you're reporting a bug, ensure it isn't already fixed in the latest axios version.
11 | - If you need a new feature there's a chance it's already implemented in a [library](https://github.com/axios/axios/blob/master/ECOSYSTEM.md) or you can implement it using [interceptors](https://github.com/axios/axios#interceptors).
12 |
13 | *^^^ Delete the instructions before submitting the issue ^^^*
14 |
15 | #### Summary
16 |
17 | Describe your issue here, including as much detail as necessary.
18 |
19 | If you're reporting a bug, include the relevant code and stack traces to debug it (removing any private information).
20 |
21 | If you're requesting a feature, include some context and examples of code using it.
22 |
23 | #### Context
24 |
25 | - axios version: *e.g.: v0.16.0*
26 | - Environment: *e.g.: node v6.9.4, chrome 54, windows 7*
27 |
--------------------------------------------------------------------------------
/examples/all/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | axios - all example
5 |
6 |
7 |
8 | axios.all
9 |
10 |
11 |
User
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
Orgs
20 |
21 |
22 |
23 |
24 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/lib/axios.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('./utils');
4 | var bind = require('./helpers/bind');
5 | var Axios = require('./core/Axios');
6 | var defaults = require('./defaults');
7 |
8 | /**
9 | * Create an instance of Axios
10 | *
11 | * @param {Object} defaultConfig The default config for the instance
12 | * @return {Axios} A new instance of Axios
13 | */
14 | function createInstance(defaultConfig) {
15 | var context = new Axios(defaultConfig);
16 | var instance = bind(Axios.prototype.request, context);
17 |
18 | // Copy axios.prototype to instance
19 | utils.extend(instance, Axios.prototype, context);
20 |
21 | // Copy context to instance
22 | utils.extend(instance, context);
23 |
24 | return instance;
25 | }
26 |
27 | // Create the default instance to be exported
28 | var axios = createInstance(defaults);
29 |
30 | // Expose Axios class to allow class inheritance
31 | axios.Axios = Axios;
32 |
33 | // Factory for creating new instances
34 | axios.create = function create(instanceConfig) {
35 | return createInstance(utils.merge(defaults, instanceConfig));
36 | };
37 |
38 | // Expose Cancel & CancelToken
39 | axios.Cancel = require('./cancel/Cancel');
40 | axios.CancelToken = require('./cancel/CancelToken');
41 | axios.isCancel = require('./cancel/isCancel');
42 |
43 | // Expose all/spread
44 | axios.all = function all(promises) {
45 | return Promise.all(promises);
46 | };
47 | axios.spread = require('./helpers/spread');
48 |
49 | module.exports = axios;
50 |
51 | // Allow use of default import syntax in TypeScript
52 | module.exports.default = axios;
53 |
--------------------------------------------------------------------------------
/lib/helpers/cookies.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('./../utils');
4 |
5 | module.exports = (
6 | utils.isStandardBrowserEnv() ?
7 |
8 | // Standard browser envs support document.cookie
9 | (function standardBrowserEnv() {
10 | return {
11 | write: function write(name, value, expires, path, domain, secure) {
12 | var cookie = [];
13 | cookie.push(name + '=' + encodeURIComponent(value));
14 |
15 | if (utils.isNumber(expires)) {
16 | cookie.push('expires=' + new Date(expires).toGMTString());
17 | }
18 |
19 | if (utils.isString(path)) {
20 | cookie.push('path=' + path);
21 | }
22 |
23 | if (utils.isString(domain)) {
24 | cookie.push('domain=' + domain);
25 | }
26 |
27 | if (secure === true) {
28 | cookie.push('secure');
29 | }
30 |
31 | document.cookie = cookie.join('; ');
32 | },
33 |
34 | read: function read(name) {
35 | var match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)'));
36 | return (match ? decodeURIComponent(match[3]) : null);
37 | },
38 |
39 | remove: function remove(name) {
40 | this.write(name, '', Date.now() - 86400000);
41 | }
42 | };
43 | })() :
44 |
45 | // Non standard browser env (web workers, react-native) lack needed support.
46 | (function nonStandardBrowserEnv() {
47 | return {
48 | write: function write() {},
49 | read: function read() { return null; },
50 | remove: function remove() {}
51 | };
52 | })()
53 | );
54 |
--------------------------------------------------------------------------------
/test/specs/helpers/parseHeaders.spec.js:
--------------------------------------------------------------------------------
1 | var parseHeaders = require('../../../lib/helpers/parseHeaders');
2 |
3 | describe('helpers::parseHeaders', function () {
4 | it('should parse headers', function () {
5 | var date = new Date();
6 | var parsed = parseHeaders(
7 | 'Date: ' + date.toISOString() + '\n' +
8 | 'Content-Type: application/json\n' +
9 | 'Connection: keep-alive\n' +
10 | 'Transfer-Encoding: chunked'
11 | );
12 |
13 | expect(parsed['date']).toEqual(date.toISOString());
14 | expect(parsed['content-type']).toEqual('application/json');
15 | expect(parsed['connection']).toEqual('keep-alive');
16 | expect(parsed['transfer-encoding']).toEqual('chunked');
17 | });
18 |
19 | it('should use array for set-cookie', function() {
20 | var parsedZero = parseHeaders('');
21 | var parsedSingle = parseHeaders(
22 | 'Set-Cookie: key=val;'
23 | );
24 | var parsedMulti = parseHeaders(
25 | 'Set-Cookie: key=val;\n' +
26 | 'Set-Cookie: key2=val2;\n'
27 | );
28 |
29 | expect(parsedZero['set-cookie']).toBeUndefined();
30 | expect(parsedSingle['set-cookie']).toEqual(['key=val;']);
31 | expect(parsedMulti['set-cookie']).toEqual(['key=val;', 'key2=val2;']);
32 | });
33 |
34 | it('should handle duplicates', function() {
35 | var parsed = parseHeaders(
36 | 'Age: age-a\n' + // age is in ignore duplicates blacklist
37 | 'Age: age-b\n' +
38 | 'Foo: foo-a\n' +
39 | 'Foo: foo-b\n'
40 | );
41 |
42 | expect(parsed['age']).toEqual('age-a');
43 | expect(parsed['foo']).toEqual('foo-a, foo-b');
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/lib/helpers/parseHeaders.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('./../utils');
4 |
5 | // Headers whose duplicates are ignored by node
6 | // c.f. https://nodejs.org/api/http.html#http_message_headers
7 | var ignoreDuplicateOf = [
8 | 'age', 'authorization', 'content-length', 'content-type', 'etag',
9 | 'expires', 'from', 'host', 'if-modified-since', 'if-unmodified-since',
10 | 'last-modified', 'location', 'max-forwards', 'proxy-authorization',
11 | 'referer', 'retry-after', 'user-agent'
12 | ];
13 |
14 | /**
15 | * Parse headers into an object
16 | *
17 | * ```
18 | * Date: Wed, 27 Aug 2014 08:58:49 GMT
19 | * Content-Type: application/json
20 | * Connection: keep-alive
21 | * Transfer-Encoding: chunked
22 | * ```
23 | *
24 | * @param {String} headers Headers needing to be parsed
25 | * @returns {Object} Headers parsed into an object
26 | */
27 | module.exports = function parseHeaders(headers) {
28 | var parsed = {};
29 | var key;
30 | var val;
31 | var i;
32 |
33 | if (!headers) { return parsed; }
34 |
35 | utils.forEach(headers.split('\n'), function parser(line) {
36 | i = line.indexOf(':');
37 | key = utils.trim(line.substr(0, i)).toLowerCase();
38 | val = utils.trim(line.substr(i + 1));
39 |
40 | if (key) {
41 | if (parsed[key] && ignoreDuplicateOf.indexOf(key) >= 0) {
42 | return;
43 | }
44 | if (key === 'set-cookie') {
45 | parsed[key] = (parsed[key] ? parsed[key] : []).concat([val]);
46 | } else {
47 | parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
48 | }
49 | }
50 | });
51 |
52 | return parsed;
53 | };
54 |
--------------------------------------------------------------------------------
/ECOSYSTEM.md:
--------------------------------------------------------------------------------
1 | # Ecosystem
2 |
3 | This is a list of axios related libraries and resources. If you have a suggestion on what to add, please don't hesitate to submit a PR.
4 |
5 | ## Libraries
6 |
7 | * [moxios](https://github.com/axios/moxios) - Mock axios requests for testing
8 | * [axios-response-logger](https://github.com/srph/axios-response-logger) - Axios interceptor which logs responses
9 | * [axios-mock-adapter](https://github.com/ctimmerm/axios-mock-adapter) — Axios adapter that allows to easily mock requests
10 | * [redux-axios-middleware](https://github.com/svrcekmichal/redux-axios-middleware) - Redux middleware for fetching data with axios HTTP client
11 | * [axios-vcr](https://github.com/nettofarah/axios-vcr) - 📼 Record and Replay Axios requests
12 | * [@3846masa/axios-cookiejar-support](https://github.com/3846masa/axios-cookiejar-support) - Add tough-cookie support to axios
13 | * [axios-debug-log](https://github.com/Gerhut/axios-debug-log) - Axios interceptor of logging requests & responses by debug.
14 | * [axios-method-override](https://github.com/jacobbuck/axios-method-override) - Axios http request method override plugin
15 | * [mocha-axios](https://github.com/jdrydn/mocha-axios) - Streamlined integration testing with Mocha & Axios
16 | * [axiosist](https://github.com/Gerhut/axiosist) - Axios based supertest: convert node.js request handler to axios adapter, used for node.js server unit test.
17 | * [axios-cache-plugin](https://github.com/jin5354/axios-cache-plugin) - Help you cache GET request when using axios.
18 | * [axios-extensions](https://github.com/kuitos/axios-extensions) - A collection of axios extensions, including throttle and cache GET request plugin.
19 |
--------------------------------------------------------------------------------
/examples/transform-response/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | axios - transform response example
5 |
6 |
7 |
8 | transformResponse
9 |
10 |
11 |
12 |
13 |
14 | Created:
15 | Updated:
16 |
17 |
18 |
19 |
20 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/examples/upload/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | axios - file upload example
5 |
6 |
7 |
8 | file upload
9 |
10 |
11 |
12 | File
13 |
14 |
15 | Upload
16 |
17 |
18 |
19 |
20 |
21 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/lib/helpers/buildURL.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('./../utils');
4 |
5 | function encode(val) {
6 | return encodeURIComponent(val).
7 | replace(/%40/gi, '@').
8 | replace(/%3A/gi, ':').
9 | replace(/%24/g, '$').
10 | replace(/%2C/gi, ',').
11 | replace(/%20/g, '+').
12 | replace(/%5B/gi, '[').
13 | replace(/%5D/gi, ']');
14 | }
15 |
16 | /**
17 | * Build a URL by appending params to the end
18 | *
19 | * @param {string} url The base of the url (e.g., http://www.google.com)
20 | * @param {object} [params] The params to be appended
21 | * @returns {string} The formatted url
22 | */
23 | module.exports = function buildURL(url, params, paramsSerializer) {
24 | /*eslint no-param-reassign:0*/
25 | if (!params) {
26 | return url;
27 | }
28 |
29 | var serializedParams;
30 | if (paramsSerializer) {
31 | serializedParams = paramsSerializer(params);
32 | } else if (utils.isURLSearchParams(params)) {
33 | serializedParams = params.toString();
34 | } else {
35 | var parts = [];
36 |
37 | utils.forEach(params, function serialize(val, key) {
38 | if (val === null || typeof val === 'undefined') {
39 | return;
40 | }
41 |
42 | if (utils.isArray(val)) {
43 | key = key + '[]';
44 | }
45 |
46 | if (!utils.isArray(val)) {
47 | val = [val];
48 | }
49 |
50 | utils.forEach(val, function parseValue(v) {
51 | if (utils.isDate(v)) {
52 | v = v.toISOString();
53 | } else if (utils.isObject(v)) {
54 | v = JSON.stringify(v);
55 | }
56 | parts.push(encode(key) + '=' + encode(v));
57 | });
58 | });
59 |
60 | serializedParams = parts.join('&');
61 | }
62 |
63 | if (serializedParams) {
64 | url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams;
65 | }
66 |
67 | return url;
68 | };
69 |
--------------------------------------------------------------------------------
/test/specs/promise.spec.js:
--------------------------------------------------------------------------------
1 | describe('promise', function () {
2 | beforeEach(function () {
3 | jasmine.Ajax.install();
4 | });
5 |
6 | afterEach(function () {
7 | jasmine.Ajax.uninstall();
8 | });
9 |
10 | it('should provide succinct object to then', function (done) {
11 | var response;
12 |
13 | axios('/foo').then(function (r) {
14 | response = r;
15 | });
16 |
17 | getAjaxRequest().then(function (request) {
18 | request.respondWith({
19 | status: 200,
20 | responseText: '{"hello":"world"}'
21 | });
22 |
23 | setTimeout(function () {
24 | expect(typeof response).toEqual('object');
25 | expect(response.data.hello).toEqual('world');
26 | expect(response.status).toEqual(200);
27 | expect(response.headers['content-type']).toEqual('application/json');
28 | expect(response.config.url).toEqual('/foo');
29 | done();
30 | }, 100);
31 | });
32 | });
33 |
34 | it('should support all', function (done) {
35 | var fulfilled = false;
36 |
37 | axios.all([true, 123]).then(function () {
38 | fulfilled = true;
39 | });
40 |
41 | setTimeout(function () {
42 | expect(fulfilled).toEqual(true);
43 | done();
44 | }, 100);
45 | });
46 |
47 | it('should support spread', function (done) {
48 | var sum = 0;
49 | var fulfilled = false;
50 | var result;
51 |
52 | axios
53 | .all([123, 456])
54 | .then(axios.spread(function (a, b) {
55 | sum = a + b;
56 | fulfilled = true;
57 | return 'hello world';
58 | }))
59 | .then(function (res) {
60 | result = res;
61 | });
62 |
63 | setTimeout(function () {
64 | expect(fulfilled).toEqual(true);
65 | expect(sum).toEqual(123 + 456);
66 | expect(result).toEqual('hello world');
67 | done();
68 | }, 100);
69 | });
70 | });
71 |
--------------------------------------------------------------------------------
/sandbox/server.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var url = require('url');
3 | var path = require('path');
4 | var http = require('http');
5 | var server;
6 |
7 | function pipeFileToResponse(res, file, type) {
8 | if (type) {
9 | res.writeHead(200, {
10 | 'Content-Type': type
11 | });
12 | }
13 |
14 | fs.createReadStream(path.join(__dirname, file)).pipe(res);
15 | }
16 |
17 | server = http.createServer(function (req, res) {
18 | req.setEncoding('utf8');
19 |
20 | var parsed = url.parse(req.url, true);
21 | var pathname = parsed.pathname;
22 |
23 | console.log('[' + new Date() + ']', req.method, pathname);
24 |
25 | if (pathname === '/') {
26 | pathname = '/index.html';
27 | }
28 |
29 | if (pathname === '/index.html') {
30 | pipeFileToResponse(res, './client.html');
31 | } else if (pathname === '/axios.js') {
32 | pipeFileToResponse(res, '../dist/axios.js', 'text/javascript');
33 | } else if (pathname === '/axios.map') {
34 | pipeFileToResponse(res, '../dist/axios.map', 'text/javascript');
35 | } else if (pathname === '/api') {
36 | var status;
37 | var result;
38 | var data = '';
39 |
40 | req.on('data', function (chunk) {
41 | data += chunk;
42 | });
43 |
44 | req.on('end', function () {
45 | try {
46 | status = 200;
47 | result = {
48 | url: req.url,
49 | data: data ? JSON.parse(data) : undefined,
50 | method: req.method,
51 | headers: req.headers
52 | };
53 | } catch (e) {
54 | console.error('Error:', e.message);
55 | status = 400;
56 | result = {
57 | error: e.message
58 | };
59 | }
60 |
61 | res.writeHead(status, {
62 | 'Content-Type': 'application/json'
63 | });
64 | res.end(JSON.stringify(result));
65 | });
66 | } else {
67 | res.writeHead(404);
68 | res.end('404 Not Found ');
69 | }
70 | });
71 |
72 | server.listen(3000);
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | We are open to, and grateful for, any contributions made by the community. By contributing to axios, you agree to abide by the [code of conduct](https://github.com/axios/axios/blob/master/CODE_OF_CONDUCT.md).
4 |
5 | ### Code Style
6 |
7 | Please follow the [node style guide](https://github.com/felixge/node-style-guide).
8 |
9 | ### Commit Messages
10 |
11 | Commit messages should be verb based, using the following pattern:
12 |
13 | - `Fixing ...`
14 | - `Adding ...`
15 | - `Updating ...`
16 | - `Removing ...`
17 |
18 | ### Testing
19 |
20 | Please update the tests to reflect your code changes. Pull requests will not be accepted if they are failing on [Travis CI](https://travis-ci.org/mzabriskie/axios).
21 |
22 | ### Documentation
23 |
24 | Please update the docs accordingly so that there are no discrepencies between the API and the documentation.
25 |
26 | ### Developing
27 |
28 | - `grunt test` run the jasmine and nodeunit tests
29 | - `grunt build` run webpack and bundle the source
30 | - `grunt version` prepare the code for release
31 | - `grunt watch:test` watch for changes and run `test`
32 | - `grunt watch:build` watch for changes and run `build`
33 |
34 | Please don't include changes to `dist/` in your pull request. This should only be updated when releasing a new version.
35 |
36 | ### Releasing
37 |
38 | Releasing a new version is mostly automated. For now the [CHANGELOG](https://github.com/axios/axios/blob/master/CHANGELOG.md) requires being updated manually. Once this has been done run the commands below. Versions should follow [semantic versioning](http://semver.org/).
39 |
40 | - `npm version -m "Releasing %s"`
41 | - `npm publish`
42 |
43 | ### Running Examples
44 |
45 | Examples are included in part to allow manual testing.
46 |
47 | Running example
48 |
49 | ```bash
50 | $ npm run examples
51 | # Open 127.0.0.1:3000
52 | ```
53 |
54 | Running sandbox in browser
55 |
56 | ```bash
57 | $ npm start
58 | # Open 127.0.0.1:3000
59 | ```
60 |
61 | Running sandbox in terminal
62 |
63 | ```bash
64 | $ npm start
65 | $ node ./sandbox/client
66 | ```
67 |
--------------------------------------------------------------------------------
/test/specs/helpers/buildURL.spec.js:
--------------------------------------------------------------------------------
1 | var buildURL = require('../../../lib/helpers/buildURL');
2 | var URLSearchParams = require('url-search-params');
3 |
4 | describe('helpers::buildURL', function () {
5 | it('should support null params', function () {
6 | expect(buildURL('/foo')).toEqual('/foo');
7 | });
8 |
9 | it('should support params', function () {
10 | expect(buildURL('/foo', {
11 | foo: 'bar'
12 | })).toEqual('/foo?foo=bar');
13 | });
14 |
15 | it('should support object params', function () {
16 | expect(buildURL('/foo', {
17 | foo: {
18 | bar: 'baz'
19 | }
20 | })).toEqual('/foo?foo=' + encodeURI('{"bar":"baz"}'));
21 | });
22 |
23 | it('should support date params', function () {
24 | var date = new Date();
25 |
26 | expect(buildURL('/foo', {
27 | date: date
28 | })).toEqual('/foo?date=' + date.toISOString());
29 | });
30 |
31 | it('should support array params', function () {
32 | expect(buildURL('/foo', {
33 | foo: ['bar', 'baz']
34 | })).toEqual('/foo?foo[]=bar&foo[]=baz');
35 | });
36 |
37 | it('should support special char params', function () {
38 | expect(buildURL('/foo', {
39 | foo: '@:$, '
40 | })).toEqual('/foo?foo=@:$,+');
41 | });
42 |
43 | it('should support existing params', function () {
44 | expect(buildURL('/foo?foo=bar', {
45 | bar: 'baz'
46 | })).toEqual('/foo?foo=bar&bar=baz');
47 | });
48 |
49 | it('should support "length" parameter', function () {
50 | expect(buildURL('/foo', {
51 | query: 'bar',
52 | start: 0,
53 | length: 5
54 | })).toEqual('/foo?query=bar&start=0&length=5');
55 | });
56 |
57 | it('should use serializer if provided', function () {
58 | serializer = sinon.stub();
59 | params = {foo: 'bar'};
60 | serializer.returns('foo=bar');
61 | expect(buildURL('/foo', params, serializer)).toEqual('/foo?foo=bar');
62 | expect(serializer.calledOnce).toBe(true);
63 | expect(serializer.calledWith(params)).toBe(true);
64 | });
65 |
66 | it('should support URLSearchParams', function () {
67 | expect(buildURL('/foo', new URLSearchParams('bar=baz'))).toEqual('/foo?bar=baz');
68 | });
69 | });
70 |
--------------------------------------------------------------------------------
/test/specs/options.spec.js:
--------------------------------------------------------------------------------
1 | describe('options', function () {
2 | beforeEach(function () {
3 | jasmine.Ajax.install();
4 | });
5 |
6 | afterEach(function () {
7 | jasmine.Ajax.uninstall();
8 | });
9 |
10 | it('should default method to get', function (done) {
11 | axios('/foo');
12 |
13 | getAjaxRequest().then(function (request) {
14 | expect(request.method).toBe('GET');
15 | done();
16 | });
17 | });
18 |
19 | it('should accept headers', function (done) {
20 | axios('/foo', {
21 | headers: {
22 | 'X-Requested-With': 'XMLHttpRequest'
23 | }
24 | });
25 |
26 | getAjaxRequest().then(function (request) {
27 | expect(request.requestHeaders['X-Requested-With']).toEqual('XMLHttpRequest');
28 | done();
29 | });
30 | });
31 |
32 | it('should accept params', function (done) {
33 | axios('/foo', {
34 | params: {
35 | foo: 123,
36 | bar: 456
37 | }
38 | });
39 |
40 | getAjaxRequest().then(function (request) {
41 | expect(request.url).toBe('/foo?foo=123&bar=456');
42 | done();
43 | });
44 | });
45 |
46 | it('should allow overriding default headers', function (done) {
47 | axios('/foo', {
48 | headers: {
49 | 'Accept': 'foo/bar'
50 | }
51 | });
52 |
53 | getAjaxRequest().then(function (request) {
54 | expect(request.requestHeaders['Accept']).toEqual('foo/bar');
55 | done();
56 | });
57 | });
58 |
59 | it('should accept base URL', function (done) {
60 | var instance = axios.create({
61 | baseURL: 'http://test.com/'
62 | });
63 |
64 | instance.get('/foo');
65 |
66 | getAjaxRequest().then(function (request) {
67 | expect(request.url).toBe('http://test.com/foo');
68 | done();
69 | });
70 | });
71 |
72 | it('should ignore base URL if request URL is absolute', function (done) {
73 | var instance = axios.create({
74 | baseURL: 'http://someurl.com/'
75 | });
76 |
77 | instance.get('http://someotherurl.com/');
78 |
79 | getAjaxRequest().then(function (request) {
80 | expect(request.url).toBe('http://someotherurl.com/');
81 | done();
82 | });
83 | });
84 | });
85 |
--------------------------------------------------------------------------------
/test/specs/transform.spec.js:
--------------------------------------------------------------------------------
1 | describe('transform', function () {
2 | beforeEach(function () {
3 | jasmine.Ajax.install();
4 | });
5 |
6 | afterEach(function () {
7 | jasmine.Ajax.uninstall();
8 | });
9 |
10 | it('should transform JSON to string', function (done) {
11 | var data = {
12 | foo: 'bar'
13 | };
14 |
15 | axios.post('/foo', data);
16 |
17 | getAjaxRequest().then(function (request) {
18 | expect(request.params).toEqual('{"foo":"bar"}');
19 | done();
20 | });
21 | });
22 |
23 | it('should transform string to JSON', function (done) {
24 | var response;
25 |
26 | axios('/foo').then(function (data) {
27 | response = data;
28 | });
29 |
30 | getAjaxRequest().then(function (request) {
31 | request.respondWith({
32 | status: 200,
33 | responseText: '{"foo": "bar"}'
34 | });
35 |
36 | setTimeout(function () {
37 | expect(typeof response.data).toEqual('object');
38 | expect(response.data.foo).toEqual('bar');
39 | done();
40 | }, 100);
41 | });
42 | });
43 |
44 | it('should override default transform', function (done) {
45 | var data = {
46 | foo: 'bar'
47 | };
48 |
49 | axios.post('/foo', data, {
50 | transformRequest: function (data) {
51 | return data;
52 | }
53 | });
54 |
55 | getAjaxRequest().then(function (request) {
56 | expect(typeof request.params).toEqual('object');
57 | done();
58 | });
59 | });
60 |
61 | it('should allow an Array of transformers', function (done) {
62 | var data = {
63 | foo: 'bar'
64 | };
65 |
66 | axios.post('/foo', data, {
67 | transformRequest: axios.defaults.transformRequest.concat(
68 | function (data) {
69 | return data.replace('bar', 'baz');
70 | }
71 | )
72 | });
73 |
74 | getAjaxRequest().then(function (request) {
75 | expect(request.params).toEqual('{"foo":"baz"}');
76 | done();
77 | });
78 | });
79 |
80 | it('should allowing mutating headers', function (done) {
81 | var token = Math.floor(Math.random() * Math.pow(2, 64)).toString(36);
82 |
83 | axios('/foo', {
84 | transformRequest: function (data, headers) {
85 | headers['X-Authorization'] = token;
86 | }
87 | });
88 |
89 | getAjaxRequest().then(function (request) {
90 | expect(request.requestHeaders['X-Authorization']).toEqual(token);
91 | done();
92 | });
93 | });
94 | });
95 |
--------------------------------------------------------------------------------
/lib/core/Axios.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var defaults = require('./../defaults');
4 | var utils = require('./../utils');
5 | var InterceptorManager = require('./InterceptorManager');
6 | var dispatchRequest = require('./dispatchRequest');
7 |
8 | /**
9 | * Create a new instance of Axios
10 | *
11 | * @param {Object} instanceConfig The default config for the instance
12 | */
13 | function Axios(instanceConfig) {
14 | this.defaults = instanceConfig;
15 | this.interceptors = {
16 | request: new InterceptorManager(),
17 | response: new InterceptorManager()
18 | };
19 | }
20 |
21 | /**
22 | * Dispatch a request
23 | *
24 | * @param {Object} config The config specific for this request (merged with this.defaults)
25 | */
26 | Axios.prototype.request = function request(config) {
27 | /*eslint no-param-reassign:0*/
28 | // Allow for axios('example/url'[, config]) a la fetch API
29 | if (typeof config === 'string') {
30 | config = utils.merge({
31 | url: arguments[0]
32 | }, arguments[1]);
33 | }
34 |
35 | config = utils.merge(defaults, this.defaults, { method: 'get' }, config);
36 | config.method = config.method.toLowerCase();
37 |
38 | // Hook up interceptors middleware
39 | var chain = [dispatchRequest, undefined];
40 | var promise = Promise.resolve(config);
41 |
42 | this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
43 | chain.unshift(interceptor.fulfilled, interceptor.rejected);
44 | });
45 |
46 | this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
47 | chain.push(interceptor.fulfilled, interceptor.rejected);
48 | });
49 |
50 | while (chain.length) {
51 | promise = promise.then(chain.shift(), chain.shift());
52 | }
53 |
54 | return promise;
55 | };
56 |
57 | // Provide aliases for supported request methods
58 | utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
59 | /*eslint func-names:0*/
60 | Axios.prototype[method] = function(url, config) {
61 | return this.request(utils.merge(config || {}, {
62 | method: method,
63 | url: url
64 | }));
65 | };
66 | });
67 |
68 | utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
69 | /*eslint func-names:0*/
70 | Axios.prototype[method] = function(url, data, config) {
71 | return this.request(utils.merge(config || {}, {
72 | method: method,
73 | url: url,
74 | data: data
75 | }));
76 | };
77 | });
78 |
79 | module.exports = Axios;
80 |
--------------------------------------------------------------------------------
/lib/helpers/isURLSameOrigin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('./../utils');
4 |
5 | module.exports = (
6 | utils.isStandardBrowserEnv() ?
7 |
8 | // Standard browser envs have full support of the APIs needed to test
9 | // whether the request URL is of the same origin as current location.
10 | (function standardBrowserEnv() {
11 | var msie = /(msie|trident)/i.test(navigator.userAgent);
12 | var urlParsingNode = document.createElement('a');
13 | var originURL;
14 |
15 | /**
16 | * Parse a URL to discover it's components
17 | *
18 | * @param {String} url The URL to be parsed
19 | * @returns {Object}
20 | */
21 | function resolveURL(url) {
22 | var href = url;
23 |
24 | if (msie) {
25 | // IE needs attribute set twice to normalize properties
26 | urlParsingNode.setAttribute('href', href);
27 | href = urlParsingNode.href;
28 | }
29 |
30 | urlParsingNode.setAttribute('href', href);
31 |
32 | // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
33 | return {
34 | href: urlParsingNode.href,
35 | protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
36 | host: urlParsingNode.host,
37 | search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
38 | hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
39 | hostname: urlParsingNode.hostname,
40 | port: urlParsingNode.port,
41 | pathname: (urlParsingNode.pathname.charAt(0) === '/') ?
42 | urlParsingNode.pathname :
43 | '/' + urlParsingNode.pathname
44 | };
45 | }
46 |
47 | originURL = resolveURL(window.location.href);
48 |
49 | /**
50 | * Determine if a URL shares the same origin as the current location
51 | *
52 | * @param {String} requestURL The URL to test
53 | * @returns {boolean} True if URL shares the same origin, otherwise false
54 | */
55 | return function isURLSameOrigin(requestURL) {
56 | var parsed = (utils.isString(requestURL)) ? resolveURL(requestURL) : requestURL;
57 | return (parsed.protocol === originURL.protocol &&
58 | parsed.host === originURL.host);
59 | };
60 | })() :
61 |
62 | // Non standard browser envs (web workers, react-native) lack needed support.
63 | (function nonStandardBrowserEnv() {
64 | return function isURLSameOrigin() {
65 | return true;
66 | };
67 | })()
68 | );
69 |
--------------------------------------------------------------------------------
/lib/core/dispatchRequest.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('./../utils');
4 | var transformData = require('./transformData');
5 | var isCancel = require('../cancel/isCancel');
6 | var defaults = require('../defaults');
7 | var isAbsoluteURL = require('./../helpers/isAbsoluteURL');
8 | var combineURLs = require('./../helpers/combineURLs');
9 |
10 | /**
11 | * Throws a `Cancel` if cancellation has been requested.
12 | */
13 | function throwIfCancellationRequested(config) {
14 | if (config.cancelToken) {
15 | config.cancelToken.throwIfRequested();
16 | }
17 | }
18 |
19 | /**
20 | * Dispatch a request to the server using the configured adapter.
21 | *
22 | * @param {object} config The config that is to be used for the request
23 | * @returns {Promise} The Promise to be fulfilled
24 | */
25 | module.exports = function dispatchRequest(config) {
26 | throwIfCancellationRequested(config);
27 |
28 | // Support baseURL config
29 | if (config.baseURL && !isAbsoluteURL(config.url)) {
30 | config.url = combineURLs(config.baseURL, config.url);
31 | }
32 |
33 | // Ensure headers exist
34 | config.headers = config.headers || {};
35 |
36 | // Transform request data
37 | config.data = transformData(
38 | config.data,
39 | config.headers,
40 | config.transformRequest
41 | );
42 |
43 | // Flatten headers
44 | config.headers = utils.merge(
45 | config.headers.common || {},
46 | config.headers[config.method] || {},
47 | config.headers || {}
48 | );
49 |
50 | utils.forEach(
51 | ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
52 | function cleanHeaderConfig(method) {
53 | delete config.headers[method];
54 | }
55 | );
56 |
57 | var adapter = config.adapter || defaults.adapter;
58 |
59 | return adapter(config).then(function onAdapterResolution(response) {
60 | throwIfCancellationRequested(config);
61 |
62 | // Transform response data
63 | response.data = transformData(
64 | response.data,
65 | response.headers,
66 | config.transformResponse
67 | );
68 |
69 | return response;
70 | }, function onAdapterRejection(reason) {
71 | if (!isCancel(reason)) {
72 | throwIfCancellationRequested(config);
73 |
74 | // Transform response data
75 | if (reason && reason.response) {
76 | reason.response.data = transformData(
77 | reason.response.data,
78 | reason.response.headers,
79 | config.transformResponse
80 | );
81 | }
82 | }
83 |
84 | return Promise.reject(reason);
85 | });
86 | };
87 |
--------------------------------------------------------------------------------
/test/specs/headers.spec.js:
--------------------------------------------------------------------------------
1 | function testHeaderValue(headers, key, val) {
2 | var found = false;
3 |
4 | for (var k in headers) {
5 | if (k.toLowerCase() === key.toLowerCase()) {
6 | found = true;
7 | expect(headers[k]).toEqual(val);
8 | break;
9 | }
10 | }
11 |
12 | if (!found) {
13 | if (typeof val === 'undefined') {
14 | expect(headers.hasOwnProperty(key)).toEqual(false);
15 | } else {
16 | throw new Error(key + ' was not found in headers');
17 | }
18 | }
19 | }
20 |
21 | describe('headers', function () {
22 | beforeEach(function () {
23 | jasmine.Ajax.install();
24 | });
25 |
26 | afterEach(function () {
27 | jasmine.Ajax.uninstall();
28 | });
29 |
30 | it('should default common headers', function (done) {
31 | var headers = axios.defaults.headers.common;
32 |
33 | axios('/foo');
34 |
35 | getAjaxRequest().then(function (request) {
36 | for (var key in headers) {
37 | if (headers.hasOwnProperty(key)) {
38 | expect(request.requestHeaders[key]).toEqual(headers[key]);
39 | }
40 | }
41 | done();
42 | });
43 | });
44 |
45 | it('should add extra headers for post', function (done) {
46 | var headers = axios.defaults.headers.common;
47 |
48 | axios.post('/foo', 'fizz=buzz');
49 |
50 | getAjaxRequest().then(function (request) {
51 | for (var key in headers) {
52 | if (headers.hasOwnProperty(key)) {
53 | expect(request.requestHeaders[key]).toEqual(headers[key]);
54 | }
55 | }
56 | done();
57 | });
58 | });
59 |
60 | it('should use application/json when posting an object', function (done) {
61 | axios.post('/foo/bar', {
62 | firstName: 'foo',
63 | lastName: 'bar'
64 | });
65 |
66 | getAjaxRequest().then(function (request) {
67 | testHeaderValue(request.requestHeaders, 'Content-Type', 'application/json;charset=utf-8');
68 | done();
69 | });
70 | });
71 |
72 | it('should remove content-type if data is empty', function (done) {
73 | axios.post('/foo');
74 |
75 | getAjaxRequest().then(function (request) {
76 | testHeaderValue(request.requestHeaders, 'Content-Type', undefined);
77 | done();
78 | });
79 | });
80 |
81 | it('should preserve content-type if data is false', function (done) {
82 | axios.post('/foo', false);
83 |
84 | getAjaxRequest().then(function (request) {
85 | testHeaderValue(request.requestHeaders, 'Content-Type', 'application/x-www-form-urlencoded');
86 | done();
87 | });
88 | });
89 | });
90 |
--------------------------------------------------------------------------------
/test/specs/api.spec.js:
--------------------------------------------------------------------------------
1 | describe('static api', function () {
2 | it('should have request method helpers', function () {
3 | expect(typeof axios.request).toEqual('function');
4 | expect(typeof axios.get).toEqual('function');
5 | expect(typeof axios.head).toEqual('function');
6 | expect(typeof axios.options).toEqual('function');
7 | expect(typeof axios.delete).toEqual('function');
8 | expect(typeof axios.post).toEqual('function');
9 | expect(typeof axios.put).toEqual('function');
10 | expect(typeof axios.patch).toEqual('function');
11 | });
12 |
13 | it('should have promise method helpers', function () {
14 | var promise = axios();
15 |
16 | expect(typeof promise.then).toEqual('function');
17 | expect(typeof promise.catch).toEqual('function');
18 | });
19 |
20 | it('should have defaults', function () {
21 | expect(typeof axios.defaults).toEqual('object');
22 | expect(typeof axios.defaults.headers).toEqual('object');
23 | });
24 |
25 | it('should have interceptors', function () {
26 | expect(typeof axios.interceptors.request).toEqual('object');
27 | expect(typeof axios.interceptors.response).toEqual('object');
28 | });
29 |
30 | it('should have all/spread helpers', function () {
31 | expect(typeof axios.all).toEqual('function');
32 | expect(typeof axios.spread).toEqual('function');
33 | });
34 |
35 | it('should have factory method', function () {
36 | expect(typeof axios.create).toEqual('function');
37 | });
38 |
39 | it('should have Cancel, CancelToken, and isCancel properties', function () {
40 | expect(typeof axios.Cancel).toEqual('function');
41 | expect(typeof axios.CancelToken).toEqual('function');
42 | expect(typeof axios.isCancel).toEqual('function');
43 | });
44 | });
45 |
46 | describe('instance api', function () {
47 | var instance = axios.create();
48 |
49 | it('should have request methods', function () {
50 | expect(typeof instance.request).toEqual('function');
51 | expect(typeof instance.get).toEqual('function');
52 | expect(typeof instance.options).toEqual('function');
53 | expect(typeof instance.head).toEqual('function');
54 | expect(typeof instance.delete).toEqual('function');
55 | expect(typeof instance.post).toEqual('function');
56 | expect(typeof instance.put).toEqual('function');
57 | expect(typeof instance.patch).toEqual('function');
58 | });
59 |
60 | it('should have interceptors', function () {
61 | expect(typeof instance.interceptors.request).toEqual('object');
62 | expect(typeof instance.interceptors.response).toEqual('object');
63 | });
64 | });
65 |
--------------------------------------------------------------------------------
/test/specs/core/settle.spec.js:
--------------------------------------------------------------------------------
1 | var settle = require('../../../lib/core/settle');
2 |
3 | describe('core::settle', function() {
4 | var resolve;
5 | var reject;
6 |
7 | beforeEach(function() {
8 | resolve = jasmine.createSpy('resolve');
9 | reject = jasmine.createSpy('reject');
10 | });
11 |
12 | it('should resolve promise if status is not set', function() {
13 | var response = {
14 | config: {
15 | validateStatus: function() {
16 | return true;
17 | }
18 | }
19 | };
20 | settle(resolve, reject, response);
21 | expect(resolve).toHaveBeenCalledWith(response);
22 | expect(reject).not.toHaveBeenCalled();
23 | });
24 |
25 | it('should resolve promise if validateStatus is not set', function() {
26 | var response = {
27 | status: 500,
28 | config: {
29 | }
30 | };
31 | settle(resolve, reject, response);
32 | expect(resolve).toHaveBeenCalledWith(response);
33 | expect(reject).not.toHaveBeenCalled();
34 | });
35 |
36 | it('should resolve promise if validateStatus returns true', function() {
37 | var response = {
38 | status: 500,
39 | config: {
40 | validateStatus: function() {
41 | return true;
42 | }
43 | }
44 | };
45 | settle(resolve, reject, response);
46 | expect(resolve).toHaveBeenCalledWith(response);
47 | expect(reject).not.toHaveBeenCalled();
48 | });
49 |
50 | it('should reject promise if validateStatus returns false', function() {
51 | var req = {
52 | path: '/foo'
53 | };
54 | var response = {
55 | status: 500,
56 | config: {
57 | validateStatus: function() {
58 | return false;
59 | }
60 | },
61 | request: req
62 | };
63 | settle(resolve, reject, response);
64 | expect(resolve).not.toHaveBeenCalled();
65 | expect(reject).toHaveBeenCalled();
66 | var reason = reject.calls.first().args[0];
67 | expect(reason instanceof Error).toBe(true);
68 | expect(reason.message).toBe('Request failed with status code 500');
69 | expect(reason.config).toBe(response.config);
70 | expect(reason.request).toBe(req);
71 | expect(reason.response).toBe(response);
72 | });
73 |
74 | it('should pass status to validateStatus', function() {
75 | var validateStatus = jasmine.createSpy('validateStatus');
76 | var response = {
77 | status: 500,
78 | config: {
79 | validateStatus: validateStatus
80 | }
81 | };
82 | settle(resolve, reject, response);
83 | expect(validateStatus).toHaveBeenCalledWith(500);
84 | });
85 | });
86 |
--------------------------------------------------------------------------------
/test/specs/xsrf.spec.js:
--------------------------------------------------------------------------------
1 | var cookies = require('../../lib/helpers/cookies');
2 |
3 | describe('xsrf', function () {
4 | beforeEach(function () {
5 | jasmine.Ajax.install();
6 | });
7 |
8 | afterEach(function () {
9 | document.cookie = axios.defaults.xsrfCookieName + '=;expires=' + new Date(Date.now() - 86400000).toGMTString();
10 | jasmine.Ajax.uninstall();
11 | });
12 |
13 | it('should not set xsrf header if cookie is null', function (done) {
14 | axios('/foo');
15 |
16 | getAjaxRequest().then(function (request) {
17 | expect(request.requestHeaders[axios.defaults.xsrfHeaderName]).toEqual(undefined);
18 | done();
19 | });
20 | });
21 |
22 | it('should set xsrf header if cookie is set', function (done) {
23 | document.cookie = axios.defaults.xsrfCookieName + '=12345';
24 |
25 | axios('/foo');
26 |
27 | getAjaxRequest().then(function (request) {
28 | expect(request.requestHeaders[axios.defaults.xsrfHeaderName]).toEqual('12345');
29 | done();
30 | });
31 | });
32 |
33 | it('should not set xsrf header if xsrfCookieName is null', function (done) {
34 | document.cookie = axios.defaults.xsrfCookieName + '=12345';
35 |
36 | axios('/foo', {
37 | xsrfCookieName: null
38 | });
39 |
40 | getAjaxRequest().then(function (request) {
41 | expect(request.requestHeaders[axios.defaults.xsrfHeaderName]).toEqual(undefined);
42 | done();
43 | });
44 | });
45 |
46 | it('should not read cookies at all if xsrfCookieName is null', function (done) {
47 | spyOn(cookies, "read");
48 |
49 | axios('/foo', {
50 | xsrfCookieName: null
51 | });
52 |
53 | getAjaxRequest().then(function (request) {
54 | expect(cookies.read).not.toHaveBeenCalled();
55 | done();
56 | });
57 | });
58 |
59 | it('should not set xsrf header for cross origin', function (done) {
60 | document.cookie = axios.defaults.xsrfCookieName + '=12345';
61 |
62 | axios('http://example.com/');
63 |
64 | getAjaxRequest().then(function (request) {
65 | expect(request.requestHeaders[axios.defaults.xsrfHeaderName]).toEqual(undefined);
66 | done();
67 | });
68 | });
69 |
70 | it('should set xsrf header for cross origin when using withCredentials', function (done) {
71 | document.cookie = axios.defaults.xsrfCookieName + '=12345';
72 |
73 | axios('http://example.com/', {
74 | withCredentials: true
75 | });
76 |
77 | getAjaxRequest().then(function (request) {
78 | expect(request.requestHeaders[axios.defaults.xsrfHeaderName]).toEqual('12345');
79 | done();
80 | });
81 | });
82 | });
83 |
--------------------------------------------------------------------------------
/lib/defaults.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('./utils');
4 | var normalizeHeaderName = require('./helpers/normalizeHeaderName');
5 |
6 | var DEFAULT_CONTENT_TYPE = {
7 | 'Content-Type': 'application/x-www-form-urlencoded'
8 | };
9 |
10 | function setContentTypeIfUnset(headers, value) {
11 | if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) {
12 | headers['Content-Type'] = value;
13 | }
14 | }
15 |
16 | function getDefaultAdapter() {
17 | var adapter;
18 | if (typeof XMLHttpRequest !== 'undefined') {
19 | // For browsers use XHR adapter
20 | adapter = require('./adapters/xhr');
21 | } else if (typeof process !== 'undefined') {
22 | // For node use HTTP adapter
23 | adapter = require('./adapters/http');
24 | }
25 | return adapter;
26 | }
27 |
28 | var defaults = {
29 | adapter: getDefaultAdapter(),
30 |
31 | transformRequest: [function transformRequest(data, headers) {
32 | normalizeHeaderName(headers, 'Content-Type');
33 | if (utils.isFormData(data) ||
34 | utils.isArrayBuffer(data) ||
35 | utils.isBuffer(data) ||
36 | utils.isStream(data) ||
37 | utils.isFile(data) ||
38 | utils.isBlob(data)
39 | ) {
40 | return data;
41 | }
42 | if (utils.isArrayBufferView(data)) {
43 | return data.buffer;
44 | }
45 | if (utils.isURLSearchParams(data)) {
46 | setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
47 | return data.toString();
48 | }
49 | if (utils.isObject(data)) {
50 | setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
51 | return JSON.stringify(data);
52 | }
53 | return data;
54 | }],
55 |
56 | transformResponse: [function transformResponse(data) {
57 | /*eslint no-param-reassign:0*/
58 | if (typeof data === 'string') {
59 | try {
60 | data = JSON.parse(data);
61 | } catch (e) { /* Ignore */ }
62 | }
63 | return data;
64 | }],
65 |
66 | timeout: 0,
67 |
68 | xsrfCookieName: 'XSRF-TOKEN',
69 | xsrfHeaderName: 'X-XSRF-TOKEN',
70 |
71 | maxContentLength: -1,
72 |
73 | validateStatus: function validateStatus(status) {
74 | return status >= 200 && status < 300;
75 | }
76 | };
77 |
78 | defaults.headers = {
79 | common: {
80 | 'Accept': 'application/json, text/plain, */*'
81 | }
82 | };
83 |
84 | utils.forEach(['delete', 'get', 'head'], function forEachMethodNoData(method) {
85 | defaults.headers[method] = {};
86 | });
87 |
88 | utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
89 | defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
90 | });
91 |
92 | module.exports = defaults;
93 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@contentful/axios",
3 | "version": "0.18.0",
4 | "description": "Promise based HTTP client for the browser and node.js",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "grunt test && bundlesize",
8 | "start": "node ./sandbox/server.js",
9 | "build": "NODE_ENV=production grunt build",
10 | "preversion": "npm test",
11 | "version": "npm run build && grunt version && git add -A dist && git add CHANGELOG.md bower.json package.json",
12 | "postversion": "git push && git push --tags",
13 | "examples": "node ./examples/server.js",
14 | "coveralls": "cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js"
15 | },
16 | "repository": {
17 | "type": "git",
18 | "url": "https://github.com/contentful/axios.git"
19 | },
20 | "keywords": [
21 | "xhr",
22 | "http",
23 | "ajax",
24 | "promise",
25 | "node"
26 | ],
27 | "author": "Matt Zabriskie",
28 | "license": "MIT",
29 | "bugs": {
30 | "url": "https://github.com/axios/axios/issues"
31 | },
32 | "homepage": "https://github.com/axios/axios",
33 | "devDependencies": {
34 | "bundlesize": "^0.5.7",
35 | "coveralls": "^2.11.9",
36 | "es6-promise": "^4.0.5",
37 | "grunt": "^1.0.1",
38 | "grunt-banner": "^0.6.0",
39 | "grunt-cli": "^1.2.0",
40 | "grunt-contrib-clean": "^1.0.0",
41 | "grunt-contrib-nodeunit": "^1.0.0",
42 | "grunt-contrib-watch": "^1.0.0",
43 | "grunt-eslint": "^19.0.0",
44 | "grunt-karma": "^2.0.0",
45 | "grunt-ts": "^6.0.0-beta.3",
46 | "grunt-webpack": "^1.0.18",
47 | "istanbul-instrumenter-loader": "^1.0.0",
48 | "jasmine-core": "^2.4.1",
49 | "karma": "^1.3.0",
50 | "karma-chrome-launcher": "^2.0.0",
51 | "karma-coverage": "^1.0.0",
52 | "karma-firefox-launcher": "^1.0.0",
53 | "karma-jasmine": "^1.0.2",
54 | "karma-jasmine-ajax": "^0.1.13",
55 | "karma-opera-launcher": "^1.0.0",
56 | "karma-phantomjs-launcher": "^1.0.0",
57 | "karma-safari-launcher": "^1.0.0",
58 | "karma-sauce-launcher": "^1.1.0",
59 | "karma-sinon": "^1.0.5",
60 | "karma-sourcemap-loader": "^0.3.7",
61 | "karma-webpack": "^1.7.0",
62 | "load-grunt-tasks": "^3.5.2",
63 | "minimist": "^1.2.0",
64 | "phantomjs-prebuilt": "^2.1.7",
65 | "sinon": "^1.17.4",
66 | "webpack": "^1.13.1",
67 | "webpack-dev-server": "^1.14.1",
68 | "url-search-params": "^0.6.1",
69 | "typescript": "^2.0.3"
70 | },
71 | "browser": {
72 | "./lib/adapters/http.js": "./lib/adapters/xhr.js"
73 | },
74 | "typings": "./index.d.ts",
75 | "dependencies": {
76 | "follow-redirects": "^1.2.5",
77 | "is-buffer": "^1.1.5"
78 | },
79 | "bundlesize": [
80 | {
81 | "path": "./dist/axios.min.js",
82 | "threshold": "5kB"
83 | }
84 | ]
85 | }
86 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | require('load-grunt-tasks')(grunt);
3 |
4 | grunt.initConfig({
5 | pkg: grunt.file.readJSON('package.json'),
6 | meta: {
7 | banner: '/* <%= pkg.name %> v<%= pkg.version %> | (c) <%= grunt.template.today("yyyy") %> by Matt Zabriskie */\n'
8 | },
9 |
10 | clean: {
11 | dist: 'dist/**'
12 | },
13 |
14 | ts: {
15 | test: {
16 | options: {
17 | lib: [
18 | 'es5',
19 | 'es2015.promise',
20 | 'dom'
21 | ]
22 | },
23 | src: ['typings/index.d.ts', 'test/typescript/*.ts']
24 | }
25 | },
26 |
27 | package2bower: {
28 | all: {
29 | fields: [
30 | 'name',
31 | 'description',
32 | 'version',
33 | 'homepage',
34 | 'license',
35 | 'keywords'
36 | ]
37 | }
38 | },
39 |
40 | usebanner: {
41 | all: {
42 | options: {
43 | banner: '<%= meta.banner %>',
44 | linebreak: false
45 | },
46 | files: {
47 | src: ['dist/*.js']
48 | }
49 | }
50 | },
51 |
52 | eslint: {
53 | target: ['lib/**/*.js']
54 | },
55 |
56 | karma: {
57 | options: {
58 | configFile: 'karma.conf.js'
59 | },
60 | single: {
61 | singleRun: true
62 | },
63 | continuous: {
64 | singleRun: false
65 | }
66 | },
67 |
68 | nodeunit: {
69 | all: ['test/unit/**/*.js']
70 | },
71 |
72 | watch: {
73 | build: {
74 | files: ['lib/**/*.js'],
75 | tasks: ['build']
76 | },
77 | test: {
78 | files: ['lib/**/*.js', 'test/**/*.js', '!test/typescript/axios.js', '!test/typescript/out.js'],
79 | tasks: ['test']
80 | }
81 | },
82 |
83 | webpack: require('./webpack.config.js')
84 | });
85 |
86 | grunt.registerMultiTask('package2bower', 'Sync package.json to bower.json', function () {
87 | var npm = grunt.file.readJSON('package.json');
88 | var bower = grunt.file.readJSON('bower.json');
89 | var fields = this.data.fields || [];
90 |
91 | for (var i=0, l=fields.length; i -1) {
23 | continue;
24 | }
25 | expect(typeof instance[prop]).toBe(typeof axios[prop]);
26 | }
27 | });
28 |
29 | it('should make an http request without verb helper', function (done) {
30 | var instance = axios.create();
31 |
32 | instance('/foo');
33 |
34 | getAjaxRequest().then(function (request) {
35 | expect(request.url).toBe('/foo');
36 | done();
37 | });
38 | });
39 |
40 | it('should make an http request', function (done) {
41 | var instance = axios.create();
42 |
43 | instance.get('/foo');
44 |
45 | getAjaxRequest().then(function (request) {
46 | expect(request.url).toBe('/foo');
47 | done();
48 | });
49 | });
50 |
51 | it('should use instance options', function (done) {
52 | var instance = axios.create({ timeout: 1000 });
53 |
54 | instance.get('/foo');
55 |
56 | getAjaxRequest().then(function (request) {
57 | expect(request.timeout).toBe(1000);
58 | done();
59 | });
60 | });
61 |
62 | it('should have defaults.headers', function () {
63 | var instance = axios.create({
64 | baseURL: 'https://api.example.com'
65 | });
66 |
67 | expect(typeof instance.defaults.headers, 'object');
68 | expect(typeof instance.defaults.headers.common, 'object');
69 | });
70 |
71 | it('should have interceptors on the instance', function (done) {
72 | axios.interceptors.request.use(function (config) {
73 | config.foo = true;
74 | return config;
75 | });
76 |
77 | var instance = axios.create();
78 | instance.interceptors.request.use(function (config) {
79 | config.bar = true;
80 | return config;
81 | });
82 |
83 | var response;
84 | instance.get('/foo').then(function (res) {
85 | response = res;
86 | });
87 |
88 | getAjaxRequest().then(function (request) {
89 | request.respondWith({
90 | status: 200
91 | });
92 |
93 | setTimeout(function () {
94 | expect(response.config.foo).toEqual(undefined);
95 | expect(response.config.bar).toEqual(true);
96 | done();
97 | }, 100);
98 | });
99 | });
100 | });
101 |
--------------------------------------------------------------------------------
/test/specs/__helpers.js:
--------------------------------------------------------------------------------
1 | // Polyfill ES6 Promise
2 | require('es6-promise').polyfill();
3 |
4 | // Polyfill URLSearchParams
5 | URLSearchParams = require('url-search-params');
6 |
7 | // Import axios
8 | axios = require('../../index');
9 |
10 | // Jasmine config
11 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;
12 | jasmine.getEnv().defaultTimeoutInterval = 20000;
13 |
14 | // Is this an old version of IE that lacks standard objects like DataView, ArrayBuffer, FormData, etc.
15 | isOldIE = /MSIE (8|9)\.0/.test(navigator.userAgent);
16 |
17 | // Get Ajax request using an increasing timeout to retry
18 | getAjaxRequest = (function () {
19 | var attempts = 0;
20 | var MAX_ATTEMPTS = 5;
21 | var ATTEMPT_DELAY_FACTOR = 5;
22 |
23 | function getAjaxRequest() {
24 | return new Promise(function (resolve, reject) {
25 | attempts = 0;
26 | attemptGettingAjaxRequest(resolve, reject);
27 | });
28 | }
29 |
30 | function attemptGettingAjaxRequest(resolve, reject) {
31 | var delay = attempts * attempts * ATTEMPT_DELAY_FACTOR;
32 |
33 | if (attempts++ > MAX_ATTEMPTS) {
34 | reject(new Error('No request was found'));
35 | return;
36 | }
37 |
38 | setTimeout(function () {
39 | var request = jasmine.Ajax.requests.mostRecent();
40 | if (request) {
41 | resolve(request);
42 | } else {
43 | attemptGettingAjaxRequest(resolve, reject);
44 | }
45 | }, delay);
46 | }
47 |
48 | return getAjaxRequest;
49 | })();
50 |
51 | // Validate an invalid character error
52 | validateInvalidCharacterError = function validateInvalidCharacterError(error) {
53 | expect(/character/i.test(error.message)).toEqual(true);
54 | };
55 |
56 | // Setup basic auth tests
57 | setupBasicAuthTest = function setupBasicAuthTest() {
58 | beforeEach(function () {
59 | jasmine.Ajax.install();
60 | });
61 |
62 | afterEach(function () {
63 | jasmine.Ajax.uninstall();
64 | });
65 |
66 | it('should accept HTTP Basic auth with username/password', function (done) {
67 | axios('/foo', {
68 | auth: {
69 | username: 'Aladdin',
70 | password: 'open sesame'
71 | }
72 | });
73 |
74 | setTimeout(function () {
75 | var request = jasmine.Ajax.requests.mostRecent();
76 |
77 | expect(request.requestHeaders['Authorization']).toEqual('Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==');
78 | done();
79 | }, 100);
80 | });
81 |
82 | it('should fail to encode HTTP Basic auth credentials with non-Latin1 characters', function (done) {
83 | axios('/foo', {
84 | auth: {
85 | username: 'Aladßç£☃din',
86 | password: 'open sesame'
87 | }
88 | }).then(function(response) {
89 | done(new Error('Should not succeed to make a HTTP Basic auth request with non-latin1 chars in credentials.'));
90 | }).catch(function(error) {
91 | validateInvalidCharacterError(error);
92 | done();
93 | });
94 | });
95 | };
96 |
--------------------------------------------------------------------------------
/test/specs/utils/isX.spec.js:
--------------------------------------------------------------------------------
1 | var utils = require('../../../lib/utils');
2 | var Stream = require('stream');
3 |
4 | describe('utils::isX', function () {
5 | it('should validate Array', function () {
6 | expect(utils.isArray([])).toEqual(true);
7 | expect(utils.isArray({length: 5})).toEqual(false);
8 | });
9 |
10 | it('should validate ArrayBuffer', function () {
11 | // ArrayBuffer doesn't exist in IE8/9
12 | if (isOldIE && typeof ArrayBuffer === 'undefined') {
13 | return;
14 | }
15 |
16 | expect(utils.isArrayBuffer(new ArrayBuffer(2))).toEqual(true);
17 | expect(utils.isArrayBuffer({})).toEqual(false);
18 | });
19 |
20 | it('should validate ArrayBufferView', function () {
21 | // ArrayBuffer doesn't exist in IE8/9
22 | if (isOldIE && typeof ArrayBuffer === 'undefined') {
23 | return;
24 | }
25 |
26 | expect(utils.isArrayBufferView(new DataView(new ArrayBuffer(2)))).toEqual(true);
27 | });
28 |
29 | it('should validate FormData', function () {
30 | // FormData doesn't exist in IE8/9
31 | if (isOldIE && typeof FormData === 'undefined') {
32 | return;
33 | }
34 |
35 | expect(utils.isFormData(new FormData())).toEqual(true);
36 | });
37 |
38 | it('should validate Blob', function () {
39 | // Blob doesn't exist in IE8/9
40 | if (isOldIE && typeof Blob === 'undefined') {
41 | return;
42 | }
43 |
44 | expect(utils.isBlob(new Blob())).toEqual(true);
45 | });
46 |
47 | it('should validate String', function () {
48 | expect(utils.isString('')).toEqual(true);
49 | expect(utils.isString({toString: function () { return ''; }})).toEqual(false);
50 | });
51 |
52 | it('should validate Number', function () {
53 | expect(utils.isNumber(123)).toEqual(true);
54 | expect(utils.isNumber('123')).toEqual(false);
55 | });
56 |
57 | it('should validate Undefined', function () {
58 | expect(utils.isUndefined()).toEqual(true);
59 | expect(utils.isUndefined(null)).toEqual(false);
60 | });
61 |
62 | it('should validate Object', function () {
63 | expect(utils.isObject({})).toEqual(true);
64 | expect(utils.isObject(null)).toEqual(false);
65 | });
66 |
67 | it('should validate Date', function () {
68 | expect(utils.isDate(new Date())).toEqual(true);
69 | expect(utils.isDate(Date.now())).toEqual(false);
70 | });
71 |
72 | it('should validate Function', function () {
73 | expect(utils.isFunction(function () {})).toEqual(true);
74 | expect(utils.isFunction('function')).toEqual(false);
75 | });
76 |
77 | it('should validate Stream', function () {
78 | expect(utils.isStream(new Stream.Readable())).toEqual(true);
79 | expect(utils.isStream({ foo: 'bar' })).toEqual(false);
80 | });
81 |
82 | it('should validate URLSearchParams', function () {
83 | expect(utils.isURLSearchParams(new URLSearchParams())).toEqual(true);
84 | expect(utils.isURLSearchParams('foo=1&bar=2')).toEqual(false);
85 | });
86 | });
87 |
--------------------------------------------------------------------------------
/COLLABORATOR_GUIDE.md:
--------------------------------------------------------------------------------
1 | # Collaborator Guide
2 |
3 | As a collaborator you will be involved with axios with some administrative responsibilities. This guide will help you understand your role and the responsibilities that come with being a collaborator.
4 |
5 | 1. __Adhere to and help enforce the Code of Conduct.__ It is expected that you have read the [code of conduct](https://github.com/axios/axios/blob/master/CODE_OF_CONDUCT.md) and that you agree to live by it. This community should be friendly and welcoming.
6 |
7 | 1. __Triage issues.__ As a collaborator you may help sort through the issues that are reported. Issues vary from bugs, regressions, feature requests, questions, etc. Apply the appropriate label(s) and respond as needed. If it is a legitimate request please address it, otherwise feel free to close the issue and include a comment with a suggestion on where to find support. If an issue has been inactive for more than a week (i.e, the owner of the issue hasn’t responded to you), close the issue with a note indicating stales issues are closed; it can always be reopened if needed. In the case of issues that require a code change encourage the owner to submit a PR. For less complex code changes, add a very simple and detailed checklist, apply the “first-timers-only” label, and encourage a newcomer to open source to get involved.
8 |
9 | 1. __Answer questions.__ It is not expected that you provide answers to questions that aren’t relevant, nor do you need to mentor people on how to use JavaScript, etc. If the question is not directly about the module, please close the issue. If the question stems from poor documentation, please update the docs and consider adding a code example. In any event try to be helpful and remember that there’s no such thing as a stupid question.
10 |
11 | 1. __Assist with PRs.__ By encouraging contributors to supply a PR for their own issue this is ideally where most of your attention will be focused. Keep a few things in mind as you review PRs.
12 | - When fixing a bug: does the PR adequately solve the problem without introducing any regressions?
13 | - When implementing a feature: does the feature fit within the scope of axios?
14 | - When removing functionality: is it properly deprecated with a warning?
15 | - When introducing functionality: is the API predictable?
16 | - Does the new code work for all supported platforms/browsers?
17 | - Do the tests and linting pass CI?
18 | - Are there tests to validate the changes that have been made?
19 |
20 | 1. __Fix bugs and implement features.__ When things need to be fixed or implemented and a PR can’t wait, you may do things yourself. You should still submit a PR yourself and get it checked off by at least one other contributor. Keep the points from number 4 in consideration as you push your code.
21 |
22 | Thank you again for your help as a collaborator and in making axios community great! If you have any questions, or need any assistance please feel free to contact another collaborator or the owner.
23 |
24 |
--------------------------------------------------------------------------------
/test/specs/cancel.spec.js:
--------------------------------------------------------------------------------
1 | var Cancel = axios.Cancel;
2 | var CancelToken = axios.CancelToken;
3 |
4 | describe('cancel', function() {
5 | beforeEach(function() {
6 | jasmine.Ajax.install();
7 | });
8 |
9 | afterEach(function() {
10 | jasmine.Ajax.uninstall();
11 | });
12 |
13 | describe('when called before sending request', function() {
14 | it('rejects Promise with a Cancel object', function (done) {
15 | var source = CancelToken.source();
16 | source.cancel('Operation has been canceled.');
17 | axios.get('/foo', {
18 | cancelToken: source.token
19 | }).catch(function (thrown) {
20 | expect(thrown).toEqual(jasmine.any(Cancel));
21 | expect(thrown.message).toBe('Operation has been canceled.');
22 | done();
23 | });
24 | });
25 | });
26 |
27 | describe('when called after request has been sent', function() {
28 | it('rejects Promise with a Cancel object', function (done) {
29 | var source = CancelToken.source();
30 | axios.get('/foo/bar', {
31 | cancelToken: source.token
32 | }).catch(function (thrown) {
33 | expect(thrown).toEqual(jasmine.any(Cancel));
34 | expect(thrown.message).toBe('Operation has been canceled.');
35 | done();
36 | });
37 |
38 | getAjaxRequest().then(function (request) {
39 | // call cancel() when the request has been sent, but a response has not been received
40 | source.cancel('Operation has been canceled.');
41 | request.respondWith({
42 | status: 200,
43 | responseText: 'OK'
44 | });
45 | });
46 | });
47 |
48 | it('calls abort on request object', function (done) {
49 | var source = CancelToken.source();
50 | var request;
51 | axios.get('/foo/bar', {
52 | cancelToken: source.token
53 | }).catch(function() {
54 | // jasmine-ajax sets statusText to 'abort' when request.abort() is called
55 | expect(request.statusText).toBe('abort');
56 | done();
57 | });
58 |
59 | getAjaxRequest().then(function (req) {
60 | // call cancel() when the request has been sent, but a response has not been received
61 | source.cancel();
62 | request = req;
63 | });
64 | });
65 | });
66 |
67 | describe('when called after response has been received', function() {
68 | // https://github.com/axios/axios/issues/482
69 | it('does not cause unhandled rejection', function (done) {
70 | var source = CancelToken.source();
71 | axios.get('/foo', {
72 | cancelToken: source.token
73 | }).then(function () {
74 | window.addEventListener('unhandledrejection', function () {
75 | done.fail('Unhandled rejection.');
76 | });
77 | source.cancel();
78 | setTimeout(done, 100);
79 | });
80 |
81 | getAjaxRequest().then(function (request) {
82 | request.respondWith({
83 | status: 200,
84 | responseText: 'OK'
85 | });
86 | });
87 | });
88 | });
89 | });
90 |
--------------------------------------------------------------------------------
/COOKBOOK.md:
--------------------------------------------------------------------------------
1 | # Cookbook
2 |
3 | In an effort to keep axios as light weight as possible, and to avoid a rats nest of code for supporting every possible integration, it is often necessary to say no to feature requests. This doesn't mean that those use cases aren't legitimate, but rather that they are easily supported by augmenting axios with other libraries.
4 |
5 | The following are the recipes for some of the commonly requested features.
6 |
7 | ### Promise.prototype.done
8 |
9 | ```bash
10 | $ npm install axios promise --save
11 | ```
12 |
13 | ```js
14 | var axios = require('axios');
15 | require('promise/polyfill-done');
16 |
17 | axios
18 | .get('http://www.example.com/user')
19 | .then(function (response) {
20 | console.log(response.data);
21 | return response;
22 | })
23 | .done();
24 | ```
25 |
26 | ### Promise.prototype.finally
27 |
28 | ```bash
29 | $ npm install axios promise.prototype.finally --save
30 | ```
31 |
32 | ```js
33 | var axios = require('axios');
34 | require('promise.prototype.finally').shim();
35 |
36 | axios
37 | .get('http://www.example.com/user')
38 | .then(function (response) {
39 | console.log(response.data);
40 | return response;
41 | })
42 | .finally(function () {
43 | console.log('this will always be called');
44 | });
45 | ```
46 |
47 | ### Inflate/Deflate
48 |
49 | ```bash
50 | $ npm install axios pako --save
51 | ```
52 |
53 | ```js
54 | // client.js
55 | var axios = require('axios');
56 | var pako = require('pako');
57 |
58 | var user = {
59 | firstName: 'Fred',
60 | lastName: 'Flintstone'
61 | };
62 |
63 | var data = pako.deflate(JSON.stringify(user), { to: 'string' });
64 |
65 | axios
66 | .post('http://127.0.0.1:3333/user', data)
67 | .then(function (response) {
68 | response.data = JSON.parse(pako.inflate(response.data, { to: 'string' }));
69 | console.log(response.data);
70 | return response;
71 | });
72 | ```
73 |
74 | ```js
75 | // server.js
76 | var pako = require('pako');
77 | var http = require('http');
78 | var url = require('url');
79 | var server;
80 |
81 | server = http.createServer(function (req, res) {
82 | req.setEncoding('utf8');
83 |
84 | var parsed = url.parse(req.url, true);
85 | var pathname = parsed.pathname;
86 |
87 | if (pathname === '/user') {
88 | var data = '';
89 | req.on('data', function (chunk) {
90 | data += chunk;
91 | });
92 |
93 | req.on('end', function () {
94 | var user = JSON.parse(pako.inflate(data, { to: 'string' }));
95 | console.log(user);
96 |
97 | res.writeHead(200, {
98 | 'Content-Type': 'application/json'
99 | });
100 | res.end(pako.deflate(JSON.stringify({result: 'success'}), { to: 'string' }));
101 | });
102 | } else {
103 | res.writeHead(404);
104 | res.end(pako.deflate(JSON.stringify({result: 'error'}), { to: 'string' }));
105 | }
106 | });
107 |
108 | server.listen(3333);
109 | ```
110 |
111 | ### JSONP
112 |
113 | ```bash
114 | $ npm install jsonp --save
115 | ```
116 |
117 | ```js
118 | var jsonp = require('jsonp');
119 |
120 | jsonp('http://www.example.com/foo', null, function (err, data) {
121 | if (err) {
122 | console.error(err.message);
123 | } else {
124 | console.log(data);
125 | }
126 | });
127 | ```
128 |
--------------------------------------------------------------------------------
/test/specs/cancel/CancelToken.spec.js:
--------------------------------------------------------------------------------
1 | var CancelToken = require('../../../lib/cancel/CancelToken');
2 | var Cancel = require('../../../lib/cancel/Cancel');
3 |
4 | describe('CancelToken', function() {
5 | describe('constructor', function() {
6 | it('throws when executor is not specified', function() {
7 | expect(function() {
8 | new CancelToken();
9 | }).toThrowError(TypeError, 'executor must be a function.');
10 | });
11 |
12 | it('throws when executor is not a function', function() {
13 | expect(function() {
14 | new CancelToken(123);
15 | }).toThrowError(TypeError, 'executor must be a function.');
16 | });
17 | });
18 |
19 | describe('reason', function() {
20 | it('returns a Cancel if cancellation has been requested', function() {
21 | var cancel;
22 | var token = new CancelToken(function(c) {
23 | cancel = c;
24 | });
25 | cancel('Operation has been canceled.');
26 | expect(token.reason).toEqual(jasmine.any(Cancel));
27 | expect(token.reason.message).toBe('Operation has been canceled.');
28 | });
29 |
30 | it('returns undefined if cancellation has not been requested', function() {
31 | var token = new CancelToken(function() {});
32 | expect(token.reason).toBeUndefined();
33 | });
34 | });
35 |
36 | describe('promise', function() {
37 | it('returns a Promise that resolves when cancellation is requested', function(done) {
38 | var cancel;
39 | var token = new CancelToken(function(c) {
40 | cancel = c;
41 | });
42 | token.promise.then(function onFulfilled(value) {
43 | expect(value).toEqual(jasmine.any(Cancel));
44 | expect(value.message).toBe('Operation has been canceled.');
45 | done();
46 | });
47 | cancel('Operation has been canceled.');
48 | });
49 | });
50 |
51 | describe('throwIfRequested', function() {
52 | it('throws if cancellation has been requested', function() {
53 | // Note: we cannot use expect.toThrowError here as Cancel does not inherit from Error
54 | var cancel;
55 | var token = new CancelToken(function(c) {
56 | cancel = c;
57 | });
58 | cancel('Operation has been canceled.');
59 | try {
60 | token.throwIfRequested();
61 | fail('Expected throwIfRequested to throw.');
62 | } catch (thrown) {
63 | if (!(thrown instanceof Cancel)) {
64 | fail('Expected throwIfRequested to throw a Cancel, but it threw ' + thrown + '.');
65 | }
66 | expect(thrown.message).toBe('Operation has been canceled.');
67 | }
68 | });
69 |
70 | it('does not throw if cancellation has not been requested', function() {
71 | var token = new CancelToken(function() {});
72 | token.throwIfRequested();
73 | });
74 | });
75 |
76 | describe('source', function() {
77 | it('returns an object containing token and cancel function', function() {
78 | var source = CancelToken.source();
79 | expect(source.token).toEqual(jasmine.any(CancelToken));
80 | expect(source.cancel).toEqual(jasmine.any(Function));
81 | expect(source.token.reason).toBeUndefined();
82 | source.cancel('Operation has been canceled.');
83 | expect(source.token.reason).toEqual(jasmine.any(Cancel));
84 | expect(source.token.reason.message).toBe('Operation has been canceled.');
85 | });
86 | });
87 | });
88 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at mzabriskie@gmail.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at [http://contributor-covenant.org/version/1/4][version]
72 |
73 | [homepage]: http://contributor-covenant.org
74 | [version]: http://contributor-covenant.org/version/1/4/
--------------------------------------------------------------------------------
/test/specs/progress.spec.js:
--------------------------------------------------------------------------------
1 | describe('progress events', function () {
2 | beforeEach(function () {
3 | jasmine.Ajax.install();
4 | });
5 |
6 | afterEach(function () {
7 | jasmine.Ajax.uninstall();
8 | });
9 |
10 | it('should add a download progress handler', function (done) {
11 | var progressSpy = jasmine.createSpy('progress');
12 |
13 | axios('/foo', { onDownloadProgress: progressSpy } );
14 |
15 | getAjaxRequest().then(function (request) {
16 | request.respondWith({
17 | status: 200,
18 | responseText: '{"foo": "bar"}'
19 | });
20 | expect(progressSpy).toHaveBeenCalled();
21 | done();
22 | });
23 | });
24 |
25 | it('should add a upload progress handler', function (done) {
26 | var progressSpy = jasmine.createSpy('progress');
27 |
28 | axios('/foo', { onUploadProgress: progressSpy } );
29 |
30 | getAjaxRequest().then(function (request) {
31 | // Jasmine AJAX doesn't trigger upload events. Waiting for upstream fix
32 | // expect(progressSpy).toHaveBeenCalled();
33 | done();
34 | });
35 | });
36 |
37 | it('should add both upload and download progress handlers', function (done) {
38 | var downloadProgressSpy = jasmine.createSpy('downloadProgress');
39 | var uploadProgressSpy = jasmine.createSpy('uploadProgress');
40 |
41 | axios('/foo', { onDownloadProgress: downloadProgressSpy, onUploadProgress: uploadProgressSpy });
42 |
43 | getAjaxRequest().then(function (request) {
44 | // expect(uploadProgressSpy).toHaveBeenCalled();
45 | expect(downloadProgressSpy).not.toHaveBeenCalled();
46 | request.respondWith({
47 | status: 200,
48 | responseText: '{"foo": "bar"}'
49 | });
50 | expect(downloadProgressSpy).toHaveBeenCalled();
51 | done();
52 | });
53 | });
54 |
55 | it('should add a download progress handler from instance config', function (done) {
56 | var progressSpy = jasmine.createSpy('progress');
57 |
58 | var instance = axios.create({
59 | onDownloadProgress: progressSpy,
60 | });
61 |
62 | instance.get('/foo');
63 |
64 | getAjaxRequest().then(function (request) {
65 | request.respondWith({
66 | status: 200,
67 | responseText: '{"foo": "bar"}'
68 | });
69 | expect(progressSpy).toHaveBeenCalled();
70 | done();
71 | });
72 | });
73 |
74 | it('should add a upload progress handler from instance config', function (done) {
75 | var progressSpy = jasmine.createSpy('progress');
76 |
77 | var instance = axios.create({
78 | onUploadProgress: progressSpy,
79 | });
80 |
81 | instance.get('/foo');
82 |
83 | getAjaxRequest().then(function (request) {
84 | // expect(progressSpy).toHaveBeenCalled();
85 | done();
86 | });
87 | });
88 |
89 | it('should add upload and download progress handlers from instance config', function (done) {
90 | var downloadProgressSpy = jasmine.createSpy('downloadProgress');
91 | var uploadProgressSpy = jasmine.createSpy('uploadProgress');
92 |
93 | var instance = axios.create({
94 | onDownloadProgress: downloadProgressSpy,
95 | onUploadProgress: uploadProgressSpy,
96 | });
97 |
98 | instance.get('/foo');
99 |
100 | getAjaxRequest().then(function (request) {
101 | // expect(uploadProgressSpy).toHaveBeenCalled();
102 | expect(downloadProgressSpy).not.toHaveBeenCalled();
103 | request.respondWith({
104 | status: 200,
105 | responseText: '{"foo": "bar"}'
106 | });
107 | expect(downloadProgressSpy).toHaveBeenCalled();
108 | done();
109 | });
110 | });
111 | });
112 |
--------------------------------------------------------------------------------
/examples/server.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var url = require('url');
3 | var path = require('path');
4 | var http = require('http');
5 | var argv = require('minimist')(process.argv.slice(2));
6 | var server;
7 | var dirs;
8 |
9 | function listDirs(root) {
10 | var files = fs.readdirSync(root);
11 | var dirs = [];
12 |
13 | for (var i=0, l=files.length; i' + url + ' ';
30 | });
31 |
32 | return (
33 | '' +
34 | '' +
35 | '' +
36 | 'axios examples ' +
37 | '' +
44 | '' +
45 | '' +
46 | links.join('') +
47 | ' '
48 | );
49 | }
50 |
51 | function sendResponse(res, statusCode, body) {
52 | res.writeHead(statusCode);
53 | res.write(body);
54 | res.end();
55 | }
56 |
57 | function send200(res, body) {
58 | sendResponse(res, 200, body || 'OK ');
59 | }
60 |
61 | function send404(res, body) {
62 | sendResponse(res, 404, body || 'Not Found ');
63 | }
64 |
65 | function pipeFileToResponse(res, file, type) {
66 | if (type) {
67 | res.writeHead(200, {
68 | 'Content-Type': type
69 | });
70 | }
71 | fs.createReadStream(path.join(__dirname, file)).pipe(res);
72 | }
73 |
74 |
75 | dirs = listDirs(__dirname);
76 |
77 | server = http.createServer(function (req, res) {
78 | var url = req.url;
79 |
80 | // Process axios itself
81 | if (/axios\.min\.js$/.test(url)) {
82 | pipeFileToResponse(res, '../dist/axios.min.js', 'text/javascript');
83 | return;
84 | }
85 | if (/axios\.min\.map$/.test(url)) {
86 | pipeFileToResponse(res, '../dist/axios.min.map', 'text/javascript');
87 | return;
88 | }
89 | if (/axios\.amd\.min\.js$/.test(url)) {
90 | pipeFileToResponse(res, '../dist/axios.amd.min.js', 'text/javascript');
91 | return;
92 | }
93 | if (/axios\.amd\.min\.map$/.test(url)) {
94 | pipeFileToResponse(res, '../dist/axios.amd.min.map', 'text/javascript');
95 | return;
96 | }
97 |
98 | // Process /
99 | if (url === '/' || url === '/index.html') {
100 | send200(res, getIndexTemplate());
101 | return;
102 | }
103 |
104 | // Format request */ -> */index.html
105 | if (/\/$/.test(url)) {
106 | url += 'index.html';
107 | }
108 |
109 | // Format request /get -> /get/index.html
110 | var parts = url.split('/');
111 | if (dirs.indexOf(parts[parts.length - 1]) > -1) {
112 | url += '/index.html';
113 | }
114 |
115 | // Process index.html request
116 | if (/index\.html$/.test(url)) {
117 | if (fs.existsSync(path.join(__dirname, url))) {
118 | pipeFileToResponse(res, url, 'text/html');
119 | } else {
120 | send404(res);
121 | }
122 | }
123 |
124 | // Process server request
125 | else if (new RegExp('(' + dirs.join('|') + ')\/server').test(url)) {
126 | if (fs.existsSync(path.join(__dirname, url + '.js'))) {
127 | require(path.join(__dirname, url + '.js'))(req, res);
128 | } else {
129 | send404(res);
130 | }
131 | }
132 | else {
133 | send404(res);
134 | }
135 | });
136 |
137 | server.listen(argv.p || 3000);
138 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | export interface AxiosTransformer {
2 | (data: any, headers?: any): any;
3 | }
4 |
5 | export interface AxiosAdapter {
6 | (config: AxiosRequestConfig): AxiosPromise;
7 | }
8 |
9 | export interface AxiosBasicCredentials {
10 | username: string;
11 | password: string;
12 | }
13 |
14 | export interface AxiosProxyConfig {
15 | host: string;
16 | port: number;
17 | auth?: {
18 | username: string;
19 | password:string;
20 | };
21 | protocol?: string;
22 | }
23 |
24 | export interface AxiosRequestConfig {
25 | url?: string;
26 | method?: string;
27 | baseURL?: string;
28 | transformRequest?: AxiosTransformer | AxiosTransformer[];
29 | transformResponse?: AxiosTransformer | AxiosTransformer[];
30 | headers?: any;
31 | params?: any;
32 | paramsSerializer?: (params: any) => string;
33 | data?: any;
34 | timeout?: number;
35 | withCredentials?: boolean;
36 | adapter?: AxiosAdapter;
37 | auth?: AxiosBasicCredentials;
38 | responseType?: string;
39 | xsrfCookieName?: string;
40 | xsrfHeaderName?: string;
41 | onUploadProgress?: (progressEvent: any) => void;
42 | onDownloadProgress?: (progressEvent: any) => void;
43 | maxContentLength?: number;
44 | validateStatus?: (status: number) => boolean;
45 | maxRedirects?: number;
46 | httpAgent?: any;
47 | httpsAgent?: any;
48 | proxy?: AxiosProxyConfig | false;
49 | cancelToken?: CancelToken;
50 | }
51 |
52 | export interface AxiosResponse {
53 | data: T;
54 | status: number;
55 | statusText: string;
56 | headers: any;
57 | config: AxiosRequestConfig;
58 | request?: any;
59 | }
60 |
61 | export interface AxiosError extends Error {
62 | config: AxiosRequestConfig;
63 | code?: string;
64 | request?: any;
65 | response?: AxiosResponse;
66 | }
67 |
68 | export interface AxiosPromise extends Promise> {
69 | }
70 |
71 | export interface CancelStatic {
72 | new (message?: string): Cancel;
73 | }
74 |
75 | export interface Cancel {
76 | message: string;
77 | }
78 |
79 | export interface Canceler {
80 | (message?: string): void;
81 | }
82 |
83 | export interface CancelTokenStatic {
84 | new (executor: (cancel: Canceler) => void): CancelToken;
85 | source(): CancelTokenSource;
86 | }
87 |
88 | export interface CancelToken {
89 | promise: Promise;
90 | reason?: Cancel;
91 | throwIfRequested(): void;
92 | }
93 |
94 | export interface CancelTokenSource {
95 | token: CancelToken;
96 | cancel: Canceler;
97 | }
98 |
99 | export interface AxiosInterceptorManager {
100 | use(onFulfilled?: (value: V) => V | Promise, onRejected?: (error: any) => any): number;
101 | eject(id: number): void;
102 | }
103 |
104 | export interface AxiosInstance {
105 | defaults: AxiosRequestConfig;
106 | interceptors: {
107 | request: AxiosInterceptorManager;
108 | response: AxiosInterceptorManager;
109 | };
110 | request(config: AxiosRequestConfig): AxiosPromise;
111 | get(url: string, config?: AxiosRequestConfig): AxiosPromise;
112 | delete(url: string, config?: AxiosRequestConfig): AxiosPromise;
113 | head(url: string, config?: AxiosRequestConfig): AxiosPromise;
114 | post(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise;
115 | put(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise;
116 | patch(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise;
117 | }
118 |
119 | export interface AxiosStatic extends AxiosInstance {
120 | (config: AxiosRequestConfig): AxiosPromise;
121 | (url: string, config?: AxiosRequestConfig): AxiosPromise;
122 | create(config?: AxiosRequestConfig): AxiosInstance;
123 | Cancel: CancelStatic;
124 | CancelToken: CancelTokenStatic;
125 | isCancel(value: any): boolean;
126 | all(values: (T | Promise)[]): Promise;
127 | spread(callback: (...args: T[]) => R): (array: T[]) => R;
128 | }
129 |
130 | declare const Axios: AxiosStatic;
131 |
132 | export default Axios;
133 |
--------------------------------------------------------------------------------
/test/specs/defaults.spec.js:
--------------------------------------------------------------------------------
1 | var defaults = require('../../lib/defaults');
2 | var utils = require('../../lib/utils');
3 |
4 | describe('defaults', function () {
5 | var XSRF_COOKIE_NAME = 'CUSTOM-XSRF-TOKEN';
6 |
7 | beforeEach(function () {
8 | jasmine.Ajax.install();
9 | });
10 |
11 | afterEach(function () {
12 | jasmine.Ajax.uninstall();
13 | delete axios.defaults.baseURL;
14 | delete axios.defaults.headers.get['X-CUSTOM-HEADER'];
15 | delete axios.defaults.headers.post['X-CUSTOM-HEADER'];
16 | document.cookie = XSRF_COOKIE_NAME + '=;expires=' + new Date(Date.now() - 86400000).toGMTString();
17 | });
18 |
19 | it('should transform request json', function () {
20 | expect(defaults.transformRequest[0]({foo: 'bar'})).toEqual('{"foo":"bar"}');
21 | });
22 |
23 | it('should do nothing to request string', function () {
24 | expect(defaults.transformRequest[0]('foo=bar')).toEqual('foo=bar');
25 | });
26 |
27 | it('should transform response json', function () {
28 | var data = defaults.transformResponse[0]('{"foo":"bar"}');
29 |
30 | expect(typeof data).toEqual('object');
31 | expect(data.foo).toEqual('bar');
32 | });
33 |
34 | it('should do nothing to response string', function () {
35 | expect(defaults.transformResponse[0]('foo=bar')).toEqual('foo=bar');
36 | });
37 |
38 | it('should use global defaults config', function (done) {
39 | axios('/foo');
40 |
41 | getAjaxRequest().then(function (request) {
42 | expect(request.url).toBe('/foo');
43 | done();
44 | });
45 | });
46 |
47 | it('should use modified defaults config', function (done) {
48 | axios.defaults.baseURL = 'http://example.com/';
49 |
50 | axios('/foo');
51 |
52 | getAjaxRequest().then(function (request) {
53 | expect(request.url).toBe('http://example.com/foo');
54 | done();
55 | });
56 | });
57 |
58 | it('should use request config', function (done) {
59 | axios('/foo', {
60 | baseURL: 'http://www.example.com'
61 | });
62 |
63 | getAjaxRequest().then(function (request) {
64 | expect(request.url).toBe('http://www.example.com/foo');
65 | done();
66 | });
67 | });
68 |
69 | it('should use default config for custom instance', function (done) {
70 | var instance = axios.create({
71 | xsrfCookieName: XSRF_COOKIE_NAME,
72 | xsrfHeaderName: 'X-CUSTOM-XSRF-TOKEN'
73 | });
74 | document.cookie = instance.defaults.xsrfCookieName + '=foobarbaz';
75 |
76 | instance.get('/foo');
77 |
78 | getAjaxRequest().then(function (request) {
79 | expect(request.requestHeaders[instance.defaults.xsrfHeaderName]).toEqual('foobarbaz');
80 | done();
81 | });
82 | });
83 |
84 | it('should use GET headers', function (done) {
85 | axios.defaults.headers.get['X-CUSTOM-HEADER'] = 'foo';
86 | axios.get('/foo');
87 |
88 | getAjaxRequest().then(function (request) {
89 | expect(request.requestHeaders['X-CUSTOM-HEADER']).toBe('foo');
90 | done();
91 | });
92 | });
93 |
94 | it('should use POST headers', function (done) {
95 | axios.defaults.headers.post['X-CUSTOM-HEADER'] = 'foo';
96 | axios.post('/foo', {});
97 |
98 | getAjaxRequest().then(function (request) {
99 | expect(request.requestHeaders['X-CUSTOM-HEADER']).toBe('foo');
100 | done();
101 | });
102 | });
103 |
104 | it('should use header config', function (done) {
105 | var instance = axios.create({
106 | headers: {
107 | common: {
108 | 'X-COMMON-HEADER': 'commonHeaderValue'
109 | },
110 | get: {
111 | 'X-GET-HEADER': 'getHeaderValue'
112 | },
113 | post: {
114 | 'X-POST-HEADER': 'postHeaderValue'
115 | }
116 | }
117 | });
118 |
119 | instance.get('/foo', {
120 | headers: {
121 | 'X-FOO-HEADER': 'fooHeaderValue',
122 | 'X-BAR-HEADER': 'barHeaderValue'
123 | }
124 | });
125 |
126 | getAjaxRequest().then(function (request) {
127 | expect(request.requestHeaders).toEqual(
128 | utils.merge(defaults.headers.common, defaults.headers.get, {
129 | 'X-COMMON-HEADER': 'commonHeaderValue',
130 | 'X-GET-HEADER': 'getHeaderValue',
131 | 'X-FOO-HEADER': 'fooHeaderValue',
132 | 'X-BAR-HEADER': 'barHeaderValue'
133 | })
134 | );
135 | done();
136 | });
137 | });
138 |
139 | it('should be used by custom instance if set before instance created', function (done) {
140 | axios.defaults.baseURL = 'http://example.org/';
141 | var instance = axios.create();
142 |
143 | instance.get('/foo');
144 |
145 | getAjaxRequest().then(function (request) {
146 | expect(request.url).toBe('http://example.org/foo');
147 | done();
148 | });
149 | });
150 |
151 | it('should be used by custom instance if set after instance created', function (done) {
152 | var instance = axios.create();
153 | axios.defaults.baseURL = 'http://example.org/';
154 |
155 | instance.get('/foo');
156 |
157 | getAjaxRequest().then(function (request) {
158 | expect(request.url).toBe('http://example.org/foo');
159 | done();
160 | });
161 | });
162 | });
163 |
--------------------------------------------------------------------------------
/UPGRADE_GUIDE.md:
--------------------------------------------------------------------------------
1 | # Upgrade Guide
2 |
3 | ### 0.15.x -> 0.16.0
4 |
5 | #### `Promise` Type Declarations
6 |
7 | The `Promise` type declarations have been removed from the axios typings in favor of the built-in type declarations. If you use axios in a TypeScript project that targets `ES5`, please make sure to include the `es2015.promise` lib. Please see [this post](https://blog.mariusschulz.com/2016/11/25/typescript-2-0-built-in-type-declarations) for details.
8 |
9 | ### 0.13.x -> 0.14.0
10 |
11 | #### TypeScript Definitions
12 |
13 | The axios TypeScript definitions have been updated to match the axios API and use the ES2015 module syntax.
14 |
15 | Please use the following `import` statement to import axios in TypeScript:
16 |
17 | ```typescript
18 | import axios from 'axios';
19 |
20 | axios.get('/foo')
21 | .then(response => console.log(response))
22 | .catch(error => console.log(error));
23 | ```
24 |
25 | #### `agent` Config Option
26 |
27 | The `agent` config option has been replaced with two new options: `httpAgent` and `httpsAgent`. Please use them instead.
28 |
29 | ```js
30 | {
31 | // Define a custom agent for HTTP
32 | httpAgent: new http.Agent({ keepAlive: true }),
33 | // Define a custom agent for HTTPS
34 | httpsAgent: new https.Agent({ keepAlive: true })
35 | }
36 | ```
37 |
38 | #### `progress` Config Option
39 |
40 | The `progress` config option has been replaced with the `onUploadProgress` and `onDownloadProgress` options.
41 |
42 | ```js
43 | {
44 | // Define a handler for upload progress events
45 | onUploadProgress: function (progressEvent) {
46 | // ...
47 | },
48 |
49 | // Define a handler for download progress events
50 | onDownloadProgress: function (progressEvent) {
51 | // ...
52 | }
53 | }
54 | ```
55 |
56 | ### 0.12.x -> 0.13.0
57 |
58 | The `0.13.0` release contains several changes to custom adapters and error handling.
59 |
60 | #### Error Handling
61 |
62 | Previous to this release an error could either be a server response with bad status code or an actual `Error`. With this release Promise will always reject with an `Error`. In the case that a response was received, the `Error` will also include the response.
63 |
64 | ```js
65 | axios.get('/user/12345')
66 | .catch((error) => {
67 | console.log(error.message);
68 | console.log(error.code); // Not always specified
69 | console.log(error.config); // The config that was used to make the request
70 | console.log(error.response); // Only available if response was received from the server
71 | });
72 | ```
73 |
74 | #### Request Adapters
75 |
76 | This release changes a few things about how request adapters work. Please take note if you are using your own custom adapter.
77 |
78 | 1. Response transformer is now called outside of adapter.
79 | 2. Request adapter returns a `Promise`.
80 |
81 | This means that you no longer need to invoke `transformData` on response data. You will also no longer receive `resolve` and `reject` as arguments in your adapter.
82 |
83 | Previous code:
84 |
85 | ```js
86 | function myAdapter(resolve, reject, config) {
87 | var response = {
88 | data: transformData(
89 | responseData,
90 | responseHeaders,
91 | config.transformResponse
92 | ),
93 | status: request.status,
94 | statusText: request.statusText,
95 | headers: responseHeaders
96 | };
97 | settle(resolve, reject, response);
98 | }
99 | ```
100 |
101 | New code:
102 |
103 | ```js
104 | function myAdapter(config) {
105 | return new Promise(function (resolve, reject) {
106 | var response = {
107 | data: responseData,
108 | status: request.status,
109 | statusText: request.statusText,
110 | headers: responseHeaders
111 | };
112 | settle(resolve, reject, response);
113 | });
114 | }
115 | ```
116 |
117 | See the related commits for more details:
118 | - [Response transformers](https://github.com/axios/axios/commit/10eb23865101f9347570552c04e9d6211376e25e)
119 | - [Request adapter Promise](https://github.com/axios/axios/commit/157efd5615890301824e3121cc6c9d2f9b21f94a)
120 |
121 | ### 0.5.x -> 0.6.0
122 |
123 | The `0.6.0` release contains mostly bug fixes, but there are a couple things to be aware of when upgrading.
124 |
125 | #### ES6 Promise Polyfill
126 |
127 | Up until the `0.6.0` release ES6 `Promise` was being polyfilled using [es6-promise](https://github.com/jakearchibald/es6-promise). With this release, the polyfill has been removed, and you will need to supply it yourself if your environment needs it.
128 |
129 | ```js
130 | require('es6-promise').polyfill();
131 | var axios = require('axios');
132 | ```
133 |
134 | This will polyfill the global environment, and only needs to be done once.
135 |
136 | #### `axios.success`/`axios.error`
137 |
138 | The `success`, and `error` aliases were deprectated in [0.4.0](https://github.com/axios/axios/blob/master/CHANGELOG.md#040-oct-03-2014). As of this release they have been removed entirely. Instead please use `axios.then`, and `axios.catch` respectively.
139 |
140 | ```js
141 | axios.get('some/url')
142 | .then(function (res) {
143 | /* ... */
144 | })
145 | .catch(function (err) {
146 | /* ... */
147 | });
148 | ```
149 |
150 | #### UMD
151 |
152 | Previous versions of axios shipped with an AMD, CommonJS, and Global build. This has all been rolled into a single UMD build.
153 |
154 | ```js
155 | // AMD
156 | require(['bower_components/axios/dist/axios'], function (axios) {
157 | /* ... */
158 | });
159 |
160 | // CommonJS
161 | var axios = require('axios/dist/axios');
162 | ```
163 |
--------------------------------------------------------------------------------
/sandbox/client.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | axios
5 |
6 |
13 |
14 |
15 | axios
16 |
17 |
18 |
Input
19 |
20 |
21 | URL
22 |
23 |
24 |
25 | Method
26 |
27 | GET
28 | POST
29 | PUT
30 | DELETE
31 | HEAD
32 | PATCH
33 |
34 |
35 |
36 | Params
37 |
38 |
39 |
40 | Data
41 |
42 |
43 |
44 | Headers
45 |
46 |
47 | Send Request
48 |
49 |
50 |
51 |
52 |
Request
53 |
No Data
54 |
55 |
56 |
57 |
Response
58 |
No Data
59 |
60 |
61 |
62 |
172 |
173 |
--------------------------------------------------------------------------------
/lib/adapters/xhr.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('./../utils');
4 | var settle = require('./../core/settle');
5 | var buildURL = require('./../helpers/buildURL');
6 | var parseHeaders = require('./../helpers/parseHeaders');
7 | var isURLSameOrigin = require('./../helpers/isURLSameOrigin');
8 | var createError = require('../core/createError');
9 | var btoa = (typeof window !== 'undefined' && window.btoa && window.btoa.bind(window)) || require('./../helpers/btoa');
10 |
11 | module.exports = function xhrAdapter(config) {
12 | return new Promise(function dispatchXhrRequest(resolve, reject) {
13 | var requestData = config.data;
14 | var requestHeaders = config.headers;
15 |
16 | if (utils.isFormData(requestData)) {
17 | delete requestHeaders['Content-Type']; // Let the browser set it
18 | }
19 |
20 | var request = new XMLHttpRequest();
21 | var loadEvent = 'onreadystatechange';
22 | var xDomain = false;
23 |
24 | // For IE 8/9 CORS support
25 | // Only supports POST and GET calls and doesn't returns the response headers.
26 | // DON'T do this for testing b/c XMLHttpRequest is mocked, not XDomainRequest.
27 | if (process.env.NODE_ENV !== 'test' &&
28 | typeof window !== 'undefined' &&
29 | window.XDomainRequest && !('withCredentials' in request) &&
30 | !isURLSameOrigin(config.url)) {
31 | request = new window.XDomainRequest();
32 | loadEvent = 'onload';
33 | xDomain = true;
34 | request.onprogress = function handleProgress() {};
35 | request.ontimeout = function handleTimeout() {};
36 | }
37 |
38 | // HTTP basic authentication
39 | if (config.auth) {
40 | var username = config.auth.username || '';
41 | var password = config.auth.password || '';
42 | requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
43 | }
44 |
45 | request.open(config.method.toUpperCase(), buildURL(config.url, config.params, config.paramsSerializer), true);
46 |
47 | // Set the request timeout in MS
48 | request.timeout = config.timeout;
49 |
50 | // Listen for ready state
51 | request[loadEvent] = function handleLoad() {
52 | if (!request || (request.readyState !== 4 && !xDomain)) {
53 | return;
54 | }
55 |
56 | // The request errored out and we didn't get a response, this will be
57 | // handled by onerror instead
58 | // With one exception: request that using file: protocol, most browsers
59 | // will return status as 0 even though it's a successful request
60 | if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
61 | return;
62 | }
63 |
64 | // Prepare the response
65 | var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
66 | var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response;
67 | var response = {
68 | data: responseData,
69 | // IE sends 1223 instead of 204 (https://github.com/axios/axios/issues/201)
70 | status: request.status === 1223 ? 204 : request.status,
71 | statusText: request.status === 1223 ? 'No Content' : request.statusText,
72 | headers: responseHeaders,
73 | config: config,
74 | request: request
75 | };
76 |
77 | settle(resolve, reject, response);
78 |
79 | // Clean up request
80 | request = null;
81 | };
82 |
83 | // Handle low level network errors
84 | request.onerror = function handleError() {
85 | // Real errors are hidden from us by the browser
86 | // onerror should only fire if it's a network error
87 | reject(createError('Network Error', config, null, request));
88 |
89 | // Clean up request
90 | request = null;
91 | };
92 |
93 | // Handle timeout
94 | request.ontimeout = function handleTimeout() {
95 | reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED',
96 | request));
97 |
98 | // Clean up request
99 | request = null;
100 | };
101 |
102 | // Add xsrf header
103 | // This is only done if running in a standard browser environment.
104 | // Specifically not if we're in a web worker, or react-native.
105 | if (utils.isStandardBrowserEnv()) {
106 | var cookies = require('./../helpers/cookies');
107 |
108 | // Add xsrf header
109 | var xsrfValue = (config.withCredentials || isURLSameOrigin(config.url)) && config.xsrfCookieName ?
110 | cookies.read(config.xsrfCookieName) :
111 | undefined;
112 |
113 | if (xsrfValue) {
114 | requestHeaders[config.xsrfHeaderName] = xsrfValue;
115 | }
116 | }
117 |
118 | // Add headers to the request
119 | if ('setRequestHeader' in request) {
120 | utils.forEach(requestHeaders, function setRequestHeader(val, key) {
121 | if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
122 | // Remove Content-Type if data is undefined
123 | delete requestHeaders[key];
124 | } else {
125 | // Otherwise add header to the request
126 | request.setRequestHeader(key, val);
127 | }
128 | });
129 | }
130 |
131 | // Add withCredentials to request if needed
132 | if (config.withCredentials) {
133 | request.withCredentials = true;
134 | }
135 |
136 | // Add responseType to request if needed
137 | if (config.responseType) {
138 | try {
139 | request.responseType = config.responseType;
140 | } catch (e) {
141 | // Expected DOMException thrown by browsers not compatible XMLHttpRequest Level 2.
142 | // But, this can be suppressed for 'json' type as it can be parsed by default 'transformResponse' function.
143 | if (config.responseType !== 'json') {
144 | throw e;
145 | }
146 | }
147 | }
148 |
149 | // Handle progress if needed
150 | if (typeof config.onDownloadProgress === 'function') {
151 | request.addEventListener('progress', config.onDownloadProgress);
152 | }
153 |
154 | // Not all browsers support upload events
155 | if (typeof config.onUploadProgress === 'function' && request.upload) {
156 | request.upload.addEventListener('progress', config.onUploadProgress);
157 | }
158 |
159 | if (config.cancelToken) {
160 | // Handle cancellation
161 | config.cancelToken.promise.then(function onCanceled(cancel) {
162 | if (!request) {
163 | return;
164 | }
165 |
166 | request.abort();
167 | reject(cancel);
168 | // Clean up request
169 | request = null;
170 | });
171 | }
172 |
173 | if (requestData === undefined) {
174 | requestData = null;
175 | }
176 |
177 | // Send the request
178 | request.send(requestData);
179 | });
180 | };
181 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Fri Aug 15 2014 23:11:13 GMT-0500 (CDT)
3 |
4 | var webpack = require('webpack');
5 |
6 | function createCustomLauncher(browser, version, platform) {
7 | return {
8 | base: 'SauceLabs',
9 | browserName: browser,
10 | version: version,
11 | platform: platform
12 | };
13 | }
14 |
15 | module.exports = function(config) {
16 | var customLaunchers = {};
17 | var browsers = [];
18 |
19 | if (process.env.SAUCE_USERNAME || process.env.SAUCE_ACCESS_KEY) {
20 | customLaunchers = {};
21 |
22 | var runAll = true;
23 | var options = [
24 | 'SAUCE_CHROME',
25 | 'SAUCE_FIREFOX',
26 | 'SAUCE_SAFARI',
27 | 'SAUCE_OPERA',
28 | 'SAUCE_IE',
29 | 'SAUCE_EDGE',
30 | 'SAUCE_IOS',
31 | 'SAUCE_ANDROID'
32 | ];
33 |
34 | options.forEach(function (opt) {
35 | if (process.env[opt]) {
36 | runAll = false;
37 | }
38 | });
39 |
40 | // Chrome
41 | if (runAll || process.env.SAUCE_CHROME) {
42 | customLaunchers.SL_Chrome = createCustomLauncher('chrome');
43 | // customLaunchers.SL_ChromeDev = createCustomLauncher('chrome', 'dev');
44 | // customLaunchers.SL_ChromeBeta = createCustomLauncher('chrome', 'beta');
45 | }
46 |
47 | // Firefox
48 | if (runAll || process.env.SAUCE_FIREFOX) {
49 | customLaunchers.SL_Firefox = createCustomLauncher('firefox');
50 | // customLaunchers.SL_FirefoxDev = createCustomLauncher('firefox', 'dev');
51 | // customLaunchers.SL_FirefoxBeta = createCustomLauncher('firefox', 'beta');
52 | }
53 |
54 | // Safari
55 | if (runAll || process.env.SAUCE_SAFARI) {
56 | // customLaunchers.SL_Safari7 = createCustomLauncher('safari', 7);
57 | // customLaunchers.SL_Safari8 = createCustomLauncher('safari', 8);
58 |
59 | customLaunchers.SL_Safari9 = createCustomLauncher('safari', 9);
60 | }
61 |
62 | // Opera
63 | if (runAll || process.env.SAUCE_OPERA) {
64 | // TODO The available versions of Opera are too old and lack basic APIs
65 | // customLaunchers.SL_Opera11 = createCustomLauncher('opera', 11, 'Windows XP');
66 | // customLaunchers.SL_Opera12 = createCustomLauncher('opera', 12, 'Windows 7');
67 | }
68 |
69 | // IE
70 | if (runAll || process.env.SAUCE_IE) {
71 | // customLaunchers.SL_IE8 = createCustomLauncher('internet explorer', 8, 'Windows 7');
72 | customLaunchers.SL_IE9 = createCustomLauncher('internet explorer', 9, 'Windows 2008');
73 | customLaunchers.SL_IE10 = createCustomLauncher('internet explorer', 10, 'Windows 2012');
74 | customLaunchers.SL_IE11 = createCustomLauncher('internet explorer', 11, 'Windows 8.1');
75 | }
76 |
77 | // Edge
78 | if (runAll || process.env.SAUCE_EDGE) {
79 | customLaunchers.SL_Edge = createCustomLauncher('microsoftedge', null, 'Windows 10');
80 | }
81 |
82 | // IOS
83 | if (runAll || process.env.SAUCE_IOS) {
84 | // TODO IOS7 capture always timesout
85 | // customLaunchers.SL_IOS7 = createCustomLauncher('iphone', '7.1', 'OS X 10.10');
86 | // TODO Mobile browsers are causing failures, possibly from too many concurrent VMs
87 | // customLaunchers.SL_IOS8 = createCustomLauncher('iphone', '8.4', 'OS X 10.10');
88 | // customLaunchers.SL_IOS9 = createCustomLauncher('iphone', '9.2', 'OS X 10.10');
89 | }
90 |
91 | // Android
92 | if (runAll || process.env.SAUCE_ANDROID) {
93 | // TODO Mobile browsers are causing failures, possibly from too many concurrent VMs
94 | // customLaunchers.SL_Android4 = createCustomLauncher('android', '4.4', 'Linux');
95 | // customLaunchers.SL_Android5 = createCustomLauncher('android', '5.1', 'Linux');
96 | }
97 |
98 | browsers = Object.keys(customLaunchers);
99 | } else if (process.env.TRAVIS_PULL_REQUEST && process.env.TRAVIS_PULL_REQUEST !== 'false') {
100 | console.log(
101 | 'Cannot run on Sauce Labs as encrypted environment variables are not available to PRs. ' +
102 | 'Running on Travis.'
103 | );
104 | browsers = ['Firefox'];
105 | } else {
106 | console.log('Running locally since SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables are not set.');
107 | browsers = ['Firefox', 'Chrome', 'Safari', 'Opera'];
108 | }
109 |
110 | config.set({
111 | // base path that will be used to resolve all patterns (eg. files, exclude)
112 | basePath: '',
113 |
114 |
115 | // frameworks to use
116 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
117 | frameworks: ['jasmine-ajax', 'jasmine', 'sinon'],
118 |
119 |
120 | // list of files / patterns to load in the browser
121 | files: [
122 | 'test/specs/__helpers.js',
123 | 'test/specs/**/*.spec.js',
124 | ],
125 |
126 |
127 | // list of files to exclude
128 | exclude: [
129 |
130 | ],
131 |
132 |
133 | // preprocess matching files before serving them to the browser
134 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
135 | preprocessors: {
136 | 'test/specs/__helpers.js': ['webpack', 'sourcemap'],
137 | 'test/specs/**/*.spec.js': ['webpack', 'sourcemap']
138 | },
139 |
140 |
141 | // test results reporter to use
142 | // possible values: 'dots', 'progress'
143 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
144 | reporters: ['dots', 'coverage', 'saucelabs'],
145 |
146 |
147 | // web server port
148 | port: 9876,
149 |
150 |
151 | // Increase timeouts to prevent the issue with disconnected tests (https://goo.gl/nstA69)
152 | captureTimeout: 4 * 60 * 1000,
153 | browserDisconnectTimeout: 10000,
154 | browserDisconnectTolerance: 1,
155 | browserNoActivityTimeout: 4 * 60 * 1000,
156 |
157 |
158 | // enable / disable colors in the output (reporters and logs)
159 | colors: true,
160 |
161 |
162 | // level of logging
163 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
164 | logLevel: config.LOG_INFO,
165 |
166 |
167 | // enable / disable watching file and executing tests whenever any file changes
168 | autoWatch: false,
169 |
170 |
171 | // start these browsers
172 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
173 | browsers: browsers,
174 |
175 |
176 | // Continuous Integration mode
177 | // if true, Karma captures browsers, runs the tests and exits
178 | singleRun: false,
179 |
180 | // Webpack config
181 | webpack: {
182 | cache: true,
183 | devtool: 'inline-source-map',
184 | module: {
185 | postLoaders: [
186 | {
187 | test: /\.js$/,
188 | exclude: /(node_modules|test)/,
189 | loader: 'istanbul-instrumenter'
190 | }
191 | ]
192 | },
193 | externals: [
194 | {
195 | './adapters/http': 'var undefined'
196 | }
197 | ],
198 | plugins: [
199 | new webpack.DefinePlugin({
200 | 'process.env.NODE_ENV': JSON.stringify('test')
201 | })
202 | ]
203 | },
204 |
205 | webpackServer: {
206 | stats: {
207 | colors: true
208 | }
209 | },
210 |
211 |
212 | // Coverage reporting
213 | coverageReporter: {
214 | type: 'lcov',
215 | dir: 'coverage/',
216 | subdir: '.'
217 | },
218 |
219 |
220 | // SauceLabs config
221 | sauceLabs: {
222 | recordScreenshots: false,
223 | connectOptions: {
224 | // port: 5757,
225 | logfile: 'sauce_connect.log'
226 | },
227 | public: 'public'
228 | },
229 |
230 | customLaunchers: customLaunchers
231 | });
232 | };
233 |
--------------------------------------------------------------------------------
/test/specs/interceptors.spec.js:
--------------------------------------------------------------------------------
1 | describe('interceptors', function () {
2 | beforeEach(function () {
3 | jasmine.Ajax.install();
4 | });
5 |
6 | afterEach(function () {
7 | jasmine.Ajax.uninstall();
8 | axios.interceptors.request.handlers = [];
9 | axios.interceptors.response.handlers = [];
10 | });
11 |
12 | it('should add a request interceptor', function (done) {
13 | axios.interceptors.request.use(function (config) {
14 | config.headers.test = 'added by interceptor';
15 | return config;
16 | });
17 |
18 | axios('/foo');
19 |
20 | getAjaxRequest().then(function (request) {
21 | request.respondWith({
22 | status: 200,
23 | responseText: 'OK'
24 | });
25 |
26 | expect(request.requestHeaders.test).toBe('added by interceptor');
27 | done();
28 | });
29 | });
30 |
31 | it('should add a request interceptor that returns a new config object', function (done) {
32 | axios.interceptors.request.use(function () {
33 | return {
34 | url: '/bar',
35 | method: 'post'
36 | };
37 | });
38 |
39 | axios('/foo');
40 |
41 | getAjaxRequest().then(function (request) {
42 | expect(request.method).toBe('POST');
43 | expect(request.url).toBe('/bar');
44 | done();
45 | });
46 | });
47 |
48 | it('should add a request interceptor that returns a promise', function (done) {
49 | axios.interceptors.request.use(function (config) {
50 | return new Promise(function (resolve) {
51 | // do something async
52 | setTimeout(function () {
53 | config.headers.async = 'promise';
54 | resolve(config);
55 | }, 100);
56 | });
57 | });
58 |
59 | axios('/foo');
60 |
61 | getAjaxRequest().then(function (request) {
62 | expect(request.requestHeaders.async).toBe('promise');
63 | done();
64 | });
65 | });
66 |
67 | it('should add multiple request interceptors', function (done) {
68 | axios.interceptors.request.use(function (config) {
69 | config.headers.test1 = '1';
70 | return config;
71 | });
72 | axios.interceptors.request.use(function (config) {
73 | config.headers.test2 = '2';
74 | return config;
75 | });
76 | axios.interceptors.request.use(function (config) {
77 | config.headers.test3 = '3';
78 | return config;
79 | });
80 |
81 | axios('/foo');
82 |
83 | getAjaxRequest().then(function (request) {
84 | expect(request.requestHeaders.test1).toBe('1');
85 | expect(request.requestHeaders.test2).toBe('2');
86 | expect(request.requestHeaders.test3).toBe('3');
87 | done();
88 | });
89 | });
90 |
91 | it('should add a response interceptor', function (done) {
92 | var response;
93 |
94 | axios.interceptors.response.use(function (data) {
95 | data.data = data.data + ' - modified by interceptor';
96 | return data;
97 | });
98 |
99 | axios('/foo').then(function (data) {
100 | response = data;
101 | });
102 |
103 | getAjaxRequest().then(function (request) {
104 | request.respondWith({
105 | status: 200,
106 | responseText: 'OK'
107 | });
108 |
109 | setTimeout(function () {
110 | expect(response.data).toBe('OK - modified by interceptor');
111 | done();
112 | }, 100);
113 | });
114 | });
115 |
116 | it('should add a response interceptor that returns a new data object', function (done) {
117 | var response;
118 |
119 | axios.interceptors.response.use(function () {
120 | return {
121 | data: 'stuff'
122 | };
123 | });
124 |
125 | axios('/foo').then(function (data) {
126 | response = data;
127 | });
128 |
129 | getAjaxRequest().then(function (request) {
130 | request.respondWith({
131 | status: 200,
132 | responseText: 'OK'
133 | });
134 |
135 | setTimeout(function () {
136 | expect(response.data).toBe('stuff');
137 | done();
138 | }, 100);
139 | });
140 | });
141 |
142 | it('should add a response interceptor that returns a promise', function (done) {
143 | var response;
144 |
145 | axios.interceptors.response.use(function (data) {
146 | return new Promise(function (resolve) {
147 | // do something async
148 | setTimeout(function () {
149 | data.data = 'you have been promised!';
150 | resolve(data);
151 | }, 10);
152 | });
153 | });
154 |
155 | axios('/foo').then(function (data) {
156 | response = data;
157 | });
158 |
159 | getAjaxRequest().then(function (request) {
160 | request.respondWith({
161 | status: 200,
162 | responseText: 'OK'
163 | });
164 |
165 | setTimeout(function () {
166 | expect(response.data).toBe('you have been promised!');
167 | done();
168 | }, 100);
169 | });
170 | });
171 |
172 | it('should add multiple response interceptors', function (done) {
173 | var response;
174 |
175 | axios.interceptors.response.use(function (data) {
176 | data.data = data.data + '1';
177 | return data;
178 | });
179 | axios.interceptors.response.use(function (data) {
180 | data.data = data.data + '2';
181 | return data;
182 | });
183 | axios.interceptors.response.use(function (data) {
184 | data.data = data.data + '3';
185 | return data;
186 | });
187 |
188 | axios('/foo').then(function (data) {
189 | response = data;
190 | });
191 |
192 | getAjaxRequest().then(function (request) {
193 | request.respondWith({
194 | status: 200,
195 | responseText: 'OK'
196 | });
197 |
198 | setTimeout(function () {
199 | expect(response.data).toBe('OK123');
200 | done();
201 | }, 100);
202 | });
203 | });
204 |
205 | it('should allow removing interceptors', function (done) {
206 | var response, intercept;
207 |
208 | axios.interceptors.response.use(function (data) {
209 | data.data = data.data + '1';
210 | return data;
211 | });
212 | intercept = axios.interceptors.response.use(function (data) {
213 | data.data = data.data + '2';
214 | return data;
215 | });
216 | axios.interceptors.response.use(function (data) {
217 | data.data = data.data + '3';
218 | return data;
219 | });
220 |
221 | axios.interceptors.response.eject(intercept);
222 |
223 | axios('/foo').then(function (data) {
224 | response = data;
225 | });
226 |
227 | getAjaxRequest().then(function (request) {
228 | request.respondWith({
229 | status: 200,
230 | responseText: 'OK'
231 | });
232 |
233 | setTimeout(function () {
234 | expect(response.data).toBe('OK13');
235 | done();
236 | }, 100);
237 | });
238 | });
239 |
240 | it('should execute interceptors before transformers', function (done) {
241 | axios.interceptors.request.use(function (config) {
242 | config.data.baz = 'qux';
243 | return config;
244 | });
245 |
246 | axios.post('/foo', {
247 | foo: 'bar'
248 | });
249 |
250 | getAjaxRequest().then(function (request) {
251 | expect(request.params).toEqual('{"foo":"bar","baz":"qux"}');
252 | done();
253 | });
254 | });
255 |
256 | it('should modify base URL in request interceptor', function (done) {
257 | var instance = axios.create({
258 | baseURL: 'http://test.com/'
259 | });
260 |
261 | instance.interceptors.request.use(function (config) {
262 | config.baseURL = 'http://rebase.com/';
263 | return config;
264 | });
265 |
266 | instance.get('/foo');
267 |
268 | getAjaxRequest().then(function (request) {
269 | expect(request.url).toBe('http://rebase.com/foo');
270 | done();
271 | });
272 | });
273 | });
274 |
--------------------------------------------------------------------------------
/test/typescript/axios.ts:
--------------------------------------------------------------------------------
1 | import axios, {
2 | AxiosRequestConfig,
3 | AxiosResponse,
4 | AxiosError,
5 | AxiosInstance,
6 | AxiosAdapter,
7 | Cancel,
8 | CancelToken,
9 | CancelTokenSource,
10 | Canceler
11 | } from '../../';
12 |
13 | const config: AxiosRequestConfig = {
14 | url: '/user',
15 | method: 'get',
16 | baseURL: 'https://api.example.com/',
17 | transformRequest: (data: any) => '{"foo":"bar"}',
18 | transformResponse: [
19 | (data: any) => ({ baz: 'qux' })
20 | ],
21 | headers: { 'X-FOO': 'bar' },
22 | params: { id: 12345 },
23 | paramsSerializer: (params: any) => 'id=12345',
24 | data: { foo: 'bar' },
25 | timeout: 10000,
26 | withCredentials: true,
27 | auth: {
28 | username: 'janedoe',
29 | password: 's00pers3cret'
30 | },
31 | responseType: 'json',
32 | xsrfCookieName: 'XSRF-TOKEN',
33 | xsrfHeaderName: 'X-XSRF-TOKEN',
34 | onUploadProgress: (progressEvent: any) => {},
35 | onDownloadProgress: (progressEvent: any) => {},
36 | maxContentLength: 2000,
37 | validateStatus: (status: number) => status >= 200 && status < 300,
38 | maxRedirects: 5,
39 | proxy: {
40 | host: '127.0.0.1',
41 | port: 9000
42 | },
43 | cancelToken: new axios.CancelToken((cancel: Canceler) => {})
44 | };
45 |
46 | const handleResponse = (response: AxiosResponse) => {
47 | console.log(response.data);
48 | console.log(response.status);
49 | console.log(response.statusText);
50 | console.log(response.headers);
51 | console.log(response.config);
52 | };
53 |
54 | const handleError = (error: AxiosError) => {
55 | if (error.response) {
56 | console.log(error.response.data);
57 | console.log(error.response.status);
58 | console.log(error.response.headers);
59 | } else {
60 | console.log(error.message);
61 | }
62 | };
63 |
64 | axios(config)
65 | .then(handleResponse)
66 | .catch(handleError);
67 |
68 | axios.get('/user?id=12345')
69 | .then(handleResponse)
70 | .catch(handleError);
71 |
72 | axios.get('/user', { params: { id: 12345 } })
73 | .then(handleResponse)
74 | .catch(handleError);
75 |
76 | axios.head('/user')
77 | .then(handleResponse)
78 | .catch(handleError);
79 |
80 | axios.delete('/user')
81 | .then(handleResponse)
82 | .catch(handleError);
83 |
84 | axios.post('/user', { foo: 'bar' })
85 | .then(handleResponse)
86 | .catch(handleError);
87 |
88 | axios.post('/user', { foo: 'bar' }, { headers: { 'X-FOO': 'bar' } })
89 | .then(handleResponse)
90 | .catch(handleError);
91 |
92 | axios.put('/user', { foo: 'bar' })
93 | .then(handleResponse)
94 | .catch(handleError);
95 |
96 | axios.patch('/user', { foo: 'bar' })
97 | .then(handleResponse)
98 | .catch(handleError);
99 |
100 | // Typed methods
101 | interface User {
102 | id: number;
103 | name: string;
104 | }
105 |
106 | const handleUserResponse = (response: AxiosResponse) => {
107 | console.log(response.data.id);
108 | console.log(response.data.name);
109 | console.log(response.status);
110 | console.log(response.statusText);
111 | console.log(response.headers);
112 | console.log(response.config);
113 | };
114 |
115 | axios.get('/user?id=12345')
116 | .then(handleUserResponse)
117 | .catch(handleError);
118 |
119 | axios.get('/user', { params: { id: 12345 } })
120 | .then(handleUserResponse)
121 | .catch(handleError);
122 |
123 | axios.post('/user', { foo: 'bar' })
124 | .then(handleUserResponse)
125 | .catch(handleError);
126 |
127 | axios.post('/user', { foo: 'bar' }, { headers: { 'X-FOO': 'bar' } })
128 | .then(handleUserResponse)
129 | .catch(handleError);
130 |
131 | axios.put('/user', { foo: 'bar' })
132 | .then(handleUserResponse)
133 | .catch(handleError);
134 |
135 | axios.patch('/user', { foo: 'bar' })
136 | .then(handleUserResponse)
137 | .catch(handleError);
138 |
139 | // Instances
140 |
141 | const instance1: AxiosInstance = axios.create();
142 | const instance2: AxiosInstance = axios.create(config);
143 |
144 | instance1.request(config)
145 | .then(handleResponse)
146 | .catch(handleError);
147 |
148 | instance1.get('/user?id=12345')
149 | .then(handleResponse)
150 | .catch(handleError);
151 |
152 | instance1.get('/user', { params: { id: 12345 } })
153 | .then(handleResponse)
154 | .catch(handleError);
155 |
156 | instance1.post('/user', { foo: 'bar' })
157 | .then(handleResponse)
158 | .catch(handleError);
159 |
160 | instance1.post('/user', { foo: 'bar' }, { headers: { 'X-FOO': 'bar' } })
161 | .then(handleResponse)
162 | .catch(handleError);
163 |
164 | // Defaults
165 |
166 | axios.defaults.baseURL = 'https://api.example.com/';
167 | axios.defaults.headers.common['Authorization'] = 'token';
168 | axios.defaults.headers.post['X-FOO'] = 'bar';
169 | axios.defaults.timeout = 2500;
170 |
171 | instance1.defaults.baseURL = 'https://api.example.com/';
172 | instance1.defaults.headers.common['Authorization'] = 'token';
173 | instance1.defaults.headers.post['X-FOO'] = 'bar';
174 | instance1.defaults.timeout = 2500;
175 |
176 | // Interceptors
177 |
178 | const requestInterceptorId: number = axios.interceptors.request.use(
179 | (config: AxiosRequestConfig) => config,
180 | (error: any) => Promise.reject(error)
181 | );
182 |
183 | axios.interceptors.request.eject(requestInterceptorId);
184 |
185 | axios.interceptors.request.use(
186 | (config: AxiosRequestConfig) => Promise.resolve(config),
187 | (error: any) => Promise.reject(error)
188 | );
189 |
190 | axios.interceptors.request.use((config: AxiosRequestConfig) => config);
191 | axios.interceptors.request.use((config: AxiosRequestConfig) => Promise.resolve(config));
192 |
193 | const responseInterceptorId: number = axios.interceptors.response.use(
194 | (response: AxiosResponse) => response,
195 | (error: any) => Promise.reject(error)
196 | );
197 |
198 | axios.interceptors.response.eject(responseInterceptorId);
199 |
200 | axios.interceptors.response.use(
201 | (response: AxiosResponse) => Promise.resolve(response),
202 | (error: any) => Promise.reject(error)
203 | );
204 |
205 | axios.interceptors.response.use((response: AxiosResponse) => response);
206 | axios.interceptors.response.use((response: AxiosResponse) => Promise.resolve(response));
207 |
208 | // Adapters
209 |
210 | const adapter: AxiosAdapter = (config: AxiosRequestConfig) => {
211 | const response: AxiosResponse = {
212 | data: { foo: 'bar' },
213 | status: 200,
214 | statusText: 'OK',
215 | headers: { 'X-FOO': 'bar' },
216 | config
217 | };
218 | return Promise.resolve(response);
219 | };
220 |
221 | axios.defaults.adapter = adapter;
222 |
223 | // axios.all
224 |
225 | const promises = [
226 | Promise.resolve(1),
227 | Promise.resolve(2)
228 | ];
229 |
230 | const promise: Promise = axios.all(promises);
231 |
232 | // axios.spread
233 |
234 | const fn1 = (a: number, b: number, c: number) => `${a}-${b}-${c}`;
235 | const fn2: (arr: number[]) => string = axios.spread(fn1);
236 |
237 | // Promises
238 |
239 | axios.get('/user')
240 | .then((response: AxiosResponse) => 'foo')
241 | .then((value: string) => {});
242 |
243 | axios.get('/user')
244 | .then((response: AxiosResponse) => Promise.resolve('foo'))
245 | .then((value: string) => {});
246 |
247 | axios.get('/user')
248 | .then((response: AxiosResponse) => 'foo', (error: any) => 'bar')
249 | .then((value: string) => {});
250 |
251 | axios.get('/user')
252 | .then((response: AxiosResponse) => 'foo', (error: any) => 123)
253 | .then((value: string | number) => {});
254 |
255 | axios.get('/user')
256 | .catch((error: any) => 'foo')
257 | .then((value: string) => {});
258 |
259 | axios.get('/user')
260 | .catch((error: any) => Promise.resolve('foo'))
261 | .then((value: string) => {});
262 |
263 | // Cancellation
264 |
265 | const source: CancelTokenSource = axios.CancelToken.source();
266 |
267 | axios.get('/user', {
268 | cancelToken: source.token
269 | }).catch((thrown: AxiosError | Cancel) => {
270 | if (axios.isCancel(thrown)) {
271 | const cancel: Cancel = thrown;
272 | console.log(cancel.message);
273 | }
274 | });
275 |
276 | source.cancel('Operation has been canceled.');
277 |
--------------------------------------------------------------------------------
/lib/adapters/http.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('./../utils');
4 | var settle = require('./../core/settle');
5 | var buildURL = require('./../helpers/buildURL');
6 | var http = require('http');
7 | var https = require('https');
8 | var httpFollow = require('follow-redirects').http;
9 | var httpsFollow = require('follow-redirects').https;
10 | var url = require('url');
11 | var zlib = require('zlib');
12 | var pkg = require('./../../package.json');
13 | var createError = require('../core/createError');
14 | var enhanceError = require('../core/enhanceError');
15 |
16 | var isHttps = /https:?/;
17 |
18 | /*eslint consistent-return:0*/
19 | module.exports = function httpAdapter(config) {
20 | return new Promise(function dispatchHttpRequest(resolve, reject) {
21 | var data = config.data;
22 | var headers = config.headers;
23 | var timer;
24 |
25 | // Set User-Agent (required by some servers)
26 | // Only set header if it hasn't been set in config
27 | // See https://github.com/axios/axios/issues/69
28 | if (!headers['User-Agent'] && !headers['user-agent']) {
29 | headers['User-Agent'] = 'axios/' + pkg.version;
30 | }
31 |
32 | if (data && !utils.isStream(data)) {
33 | if (Buffer.isBuffer(data)) {
34 | // Nothing to do...
35 | } else if (utils.isArrayBuffer(data)) {
36 | data = new Buffer(new Uint8Array(data));
37 | } else if (utils.isString(data)) {
38 | data = new Buffer(data, 'utf-8');
39 | } else {
40 | return reject(createError(
41 | 'Data after transformation must be a string, an ArrayBuffer, a Buffer, or a Stream',
42 | config
43 | ));
44 | }
45 |
46 | // Add Content-Length header if data exists
47 | headers['Content-Length'] = data.length;
48 | }
49 |
50 | // HTTP basic authentication
51 | var auth = undefined;
52 | if (config.auth) {
53 | var username = config.auth.username || '';
54 | var password = config.auth.password || '';
55 | auth = username + ':' + password;
56 | }
57 |
58 | // Parse url
59 | var parsed = url.parse(config.url);
60 | var protocol = parsed.protocol || 'http:';
61 |
62 | if (!auth && parsed.auth) {
63 | var urlAuth = parsed.auth.split(':');
64 | var urlUsername = urlAuth[0] || '';
65 | var urlPassword = urlAuth[1] || '';
66 | auth = urlUsername + ':' + urlPassword;
67 | }
68 |
69 | if (auth) {
70 | delete headers.Authorization;
71 | }
72 |
73 | var isHttpsRequest = isHttps.test(protocol);
74 | var agent = isHttpsRequest ? config.httpsAgent : config.httpAgent;
75 |
76 | var options = {
77 | hostname: parsed.hostname,
78 | port: parsed.port,
79 | path: buildURL(parsed.path, config.params, config.paramsSerializer).replace(/^\?/, ''),
80 | method: config.method,
81 | headers: headers,
82 | agent: agent,
83 | auth: auth
84 | };
85 |
86 | var proxy = config.proxy;
87 | if (!proxy && proxy !== false) {
88 | var proxyEnv = protocol.slice(0, -1) + '_proxy';
89 | var proxyUrl = process.env[proxyEnv] || process.env[proxyEnv.toUpperCase()];
90 | if (proxyUrl) {
91 | var parsedProxyUrl = url.parse(proxyUrl);
92 | proxy = {
93 | host: parsedProxyUrl.hostname,
94 | port: parsedProxyUrl.port
95 | };
96 |
97 | if (parsedProxyUrl.auth) {
98 | var proxyUrlAuth = parsedProxyUrl.auth.split(':');
99 | proxy.auth = {
100 | username: proxyUrlAuth[0],
101 | password: proxyUrlAuth[1]
102 | };
103 | }
104 | }
105 | }
106 |
107 | if (proxy) {
108 | options.hostname = proxy.host;
109 | options.host = proxy.host;
110 | options.headers.host = parsed.hostname + (parsed.port ? ':' + parsed.port : '');
111 | options.port = proxy.port;
112 | options.path = protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path;
113 |
114 | // Basic proxy authorization
115 | if (proxy.auth) {
116 | var base64 = new Buffer(proxy.auth.username + ':' + proxy.auth.password, 'utf8').toString('base64');
117 | options.headers['Proxy-Authorization'] = 'Basic ' + base64;
118 | }
119 | }
120 |
121 | var transport;
122 | var isHttpsProxy = isHttpsRequest && (proxy ? isHttps.test(proxy.protocol) : true);
123 | if (config.transport) {
124 | transport = config.transport;
125 | } else if (config.maxRedirects === 0) {
126 | transport = isHttpsProxy ? https : http;
127 | } else {
128 | if (config.maxRedirects) {
129 | options.maxRedirects = config.maxRedirects;
130 | }
131 | transport = isHttpsProxy ? httpsFollow : httpFollow;
132 | }
133 |
134 | // Create the request
135 | var req = transport.request(options, function handleResponse(res) {
136 | if (req.aborted) return;
137 |
138 | // Response has been received so kill timer that handles request timeout
139 | clearTimeout(timer);
140 | timer = null;
141 |
142 | // uncompress the response body transparently if required
143 | var stream = res;
144 | switch (res.headers['content-encoding']) {
145 | /*eslint default-case:0*/
146 | case 'gzip':
147 | case 'compress':
148 | case 'deflate':
149 | // add the unzipper to the body stream processing pipeline
150 | stream = stream.pipe(zlib.createUnzip());
151 |
152 | // remove the content-encoding in order to not confuse downstream operations
153 | delete res.headers['content-encoding'];
154 | break;
155 | }
156 |
157 | // return the last request in case of redirects
158 | var lastRequest = res.req || req;
159 |
160 | var response = {
161 | status: res.statusCode,
162 | statusText: res.statusMessage,
163 | headers: res.headers,
164 | config: config,
165 | request: lastRequest
166 | };
167 |
168 | if (config.responseType === 'stream') {
169 | response.data = stream;
170 | settle(resolve, reject, response);
171 | } else {
172 | var responseBuffer = [];
173 | stream.on('data', function handleStreamData(chunk) {
174 | responseBuffer.push(chunk);
175 |
176 | // make sure the content length is not over the maxContentLength if specified
177 | if (config.maxContentLength > -1 && Buffer.concat(responseBuffer).length > config.maxContentLength) {
178 | reject(createError('maxContentLength size of ' + config.maxContentLength + ' exceeded',
179 | config, null, lastRequest));
180 | }
181 | });
182 |
183 | stream.on('error', function handleStreamError(err) {
184 | if (req.aborted) return;
185 | reject(enhanceError(err, config, null, lastRequest));
186 | });
187 |
188 | stream.on('end', function handleStreamEnd() {
189 | var responseData = Buffer.concat(responseBuffer);
190 | if (config.responseType !== 'arraybuffer') {
191 | responseData = responseData.toString('utf8');
192 | }
193 |
194 | response.data = responseData;
195 | settle(resolve, reject, response);
196 | });
197 | }
198 | });
199 |
200 | // Handle errors
201 | req.on('error', function handleRequestError(err) {
202 | if (req.aborted) return;
203 | reject(enhanceError(err, config, null, req));
204 | });
205 |
206 | // Handle request timeout
207 | if (config.timeout && !timer) {
208 | timer = setTimeout(function handleRequestTimeout() {
209 | req.abort();
210 | reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED', req));
211 | }, config.timeout);
212 | }
213 |
214 | if (config.cancelToken) {
215 | // Handle cancellation
216 | config.cancelToken.promise.then(function onCanceled(cancel) {
217 | if (req.aborted) return;
218 |
219 | req.abort();
220 | reject(cancel);
221 | });
222 | }
223 |
224 | // Send the request
225 | if (utils.isStream(data)) {
226 | data.pipe(req);
227 | } else {
228 | req.end(data);
229 | }
230 | });
231 | };
232 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "globals": {
3 | "console": true,
4 | "module": true,
5 | "require": true
6 | },
7 | "env": {
8 | "browser": true,
9 | "node": true
10 | },
11 | "rules": {
12 | /**
13 | * Strict mode
14 | */
15 | "strict": [2, "global"], // http://eslint.org/docs/rules/strict
16 |
17 | /**
18 | * Variables
19 | */
20 | "no-shadow": 2, // http://eslint.org/docs/rules/no-shadow
21 | "no-shadow-restricted-names": 2, // http://eslint.org/docs/rules/no-shadow-restricted-names
22 | "no-unused-vars": [2, { // http://eslint.org/docs/rules/no-unused-vars
23 | "vars": "local",
24 | "args": "after-used"
25 | }],
26 | "no-use-before-define": 2, // http://eslint.org/docs/rules/no-use-before-define
27 |
28 | /**
29 | * Possible errors
30 | */
31 | "comma-dangle": [2, "never"], // http://eslint.org/docs/rules/comma-dangle
32 | "no-cond-assign": [2, "except-parens"], // http://eslint.org/docs/rules/no-cond-assign
33 | "no-console": 1, // http://eslint.org/docs/rules/no-console
34 | "no-debugger": 1, // http://eslint.org/docs/rules/no-debugger
35 | "no-alert": 1, // http://eslint.org/docs/rules/no-alert
36 | "no-constant-condition": 1, // http://eslint.org/docs/rules/no-constant-condition
37 | "no-dupe-keys": 2, // http://eslint.org/docs/rules/no-dupe-keys
38 | "no-duplicate-case": 2, // http://eslint.org/docs/rules/no-duplicate-case
39 | "no-empty": 2, // http://eslint.org/docs/rules/no-empty
40 | "no-ex-assign": 2, // http://eslint.org/docs/rules/no-ex-assign
41 | "no-extra-boolean-cast": 0, // http://eslint.org/docs/rules/no-extra-boolean-cast
42 | "no-extra-semi": 2, // http://eslint.org/docs/rules/no-extra-semi
43 | "no-func-assign": 2, // http://eslint.org/docs/rules/no-func-assign
44 | "no-inner-declarations": 2, // http://eslint.org/docs/rules/no-inner-declarations
45 | "no-invalid-regexp": 2, // http://eslint.org/docs/rules/no-invalid-regexp
46 | "no-irregular-whitespace": 2, // http://eslint.org/docs/rules/no-irregular-whitespace
47 | "no-obj-calls": 2, // http://eslint.org/docs/rules/no-obj-calls
48 | "no-sparse-arrays": 2, // http://eslint.org/docs/rules/no-sparse-arrays
49 | "no-unreachable": 2, // http://eslint.org/docs/rules/no-unreachable
50 | "use-isnan": 2, // http://eslint.org/docs/rules/use-isnan
51 | "block-scoped-var": 2, // http://eslint.org/docs/rules/block-scoped-var
52 |
53 | /**
54 | * Best practices
55 | */
56 | "consistent-return": 2, // http://eslint.org/docs/rules/consistent-return
57 | "curly": [2, "multi-line"], // http://eslint.org/docs/rules/curly
58 | "default-case": 2, // http://eslint.org/docs/rules/default-case
59 | "dot-notation": [2, { // http://eslint.org/docs/rules/dot-notation
60 | "allowKeywords": true
61 | }],
62 | "eqeqeq": 2, // http://eslint.org/docs/rules/eqeqeq
63 | "guard-for-in": 2, // http://eslint.org/docs/rules/guard-for-in
64 | "no-caller": 2, // http://eslint.org/docs/rules/no-caller
65 | "no-else-return": 2, // http://eslint.org/docs/rules/no-else-return
66 | "no-eq-null": 2, // http://eslint.org/docs/rules/no-eq-null
67 | "no-eval": 2, // http://eslint.org/docs/rules/no-eval
68 | "no-extend-native": 2, // http://eslint.org/docs/rules/no-extend-native
69 | "no-extra-bind": 2, // http://eslint.org/docs/rules/no-extra-bind
70 | "no-fallthrough": 2, // http://eslint.org/docs/rules/no-fallthrough
71 | "no-floating-decimal": 2, // http://eslint.org/docs/rules/no-floating-decimal
72 | "no-implied-eval": 2, // http://eslint.org/docs/rules/no-implied-eval
73 | "no-lone-blocks": 2, // http://eslint.org/docs/rules/no-lone-blocks
74 | "no-loop-func": 2, // http://eslint.org/docs/rules/no-loop-func
75 | "no-multi-str": 2, // http://eslint.org/docs/rules/no-multi-str
76 | "no-native-reassign": 2, // http://eslint.org/docs/rules/no-native-reassign
77 | "no-new": 2, // http://eslint.org/docs/rules/no-new
78 | "no-new-func": 2, // http://eslint.org/docs/rules/no-new-func
79 | "no-new-wrappers": 2, // http://eslint.org/docs/rules/no-new-wrappers
80 | "no-octal": 2, // http://eslint.org/docs/rules/no-octal
81 | "no-octal-escape": 2, // http://eslint.org/docs/rules/no-octal-escape
82 | "no-param-reassign": 2, // http://eslint.org/docs/rules/no-param-reassign
83 | "no-proto": 2, // http://eslint.org/docs/rules/no-proto
84 | "no-redeclare": 2, // http://eslint.org/docs/rules/no-redeclare
85 | "no-return-assign": 2, // http://eslint.org/docs/rules/no-return-assign
86 | "no-script-url": 2, // http://eslint.org/docs/rules/no-script-url
87 | "no-self-compare": 2, // http://eslint.org/docs/rules/no-self-compare
88 | "no-sequences": 2, // http://eslint.org/docs/rules/no-sequences
89 | "no-throw-literal": 2, // http://eslint.org/docs/rules/no-throw-literal
90 | "no-with": 2, // http://eslint.org/docs/rules/no-with
91 | "radix": 2, // http://eslint.org/docs/rules/radix
92 | "vars-on-top": 0, // http://eslint.org/docs/rules/vars-on-top
93 | "wrap-iife": [2, "any"], // http://eslint.org/docs/rules/wrap-iife
94 | "yoda": 2, // http://eslint.org/docs/rules/yoda
95 |
96 | /**
97 | * Style
98 | */
99 | "indent": [2, 2], // http://eslint.org/docs/rules/indent
100 | "brace-style": [2, // http://eslint.org/docs/rules/brace-style
101 | "1tbs", {
102 | "allowSingleLine": true
103 | }],
104 | "quotes": [
105 | 2, "single", "avoid-escape" // http://eslint.org/docs/rules/quotes
106 | ],
107 | "camelcase": [2, { // http://eslint.org/docs/rules/camelcase
108 | "properties": "never"
109 | }],
110 | "comma-spacing": [2, { // http://eslint.org/docs/rules/comma-spacing
111 | "before": false,
112 | "after": true
113 | }],
114 | "comma-style": [2, "last"], // http://eslint.org/docs/rules/comma-style
115 | "eol-last": 2, // http://eslint.org/docs/rules/eol-last
116 | "func-names": 1, // http://eslint.org/docs/rules/func-names
117 | "key-spacing": [2, { // http://eslint.org/docs/rules/key-spacing
118 | "beforeColon": false,
119 | "afterColon": true
120 | }],
121 | "new-cap": [2, { // http://eslint.org/docs/rules/new-cap
122 | "newIsCap": true
123 | }],
124 | "no-multiple-empty-lines": [2, { // http://eslint.org/docs/rules/no-multiple-empty-lines
125 | "max": 2
126 | }],
127 | "no-nested-ternary": 2, // http://eslint.org/docs/rules/no-nested-ternary
128 | "no-new-object": 2, // http://eslint.org/docs/rules/no-new-object
129 | "no-spaced-func": 2, // http://eslint.org/docs/rules/no-spaced-func
130 | "no-trailing-spaces": 2, // http://eslint.org/docs/rules/no-trailing-spaces
131 | "no-extra-parens": [2, "functions"], // http://eslint.org/docs/rules/no-extra-parens
132 | "no-underscore-dangle": 0, // http://eslint.org/docs/rules/no-underscore-dangle
133 | "one-var": [2, "never"], // http://eslint.org/docs/rules/one-var
134 | "padded-blocks": [2, "never"], // http://eslint.org/docs/rules/padded-blocks
135 | "semi": [2, "always"], // http://eslint.org/docs/rules/semi
136 | "semi-spacing": [2, { // http://eslint.org/docs/rules/semi-spacing
137 | "before": false,
138 | "after": true
139 | }],
140 | "keyword-spacing": 2, // http://eslint.org/docs/rules/keyword-spacing
141 | "space-before-blocks": 2, // http://eslint.org/docs/rules/space-before-blocks
142 | "space-before-function-paren": [2, "never"], // http://eslint.org/docs/rules/space-before-function-paren
143 | "space-infix-ops": 2, // http://eslint.org/docs/rules/space-infix-ops
144 | "spaced-comment": [2, "always", {// http://eslint.org/docs/rules/spaced-comment
145 | "markers": ["global", "eslint"]
146 | }]
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/lib/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var bind = require('./helpers/bind');
4 | var isBuffer = require('is-buffer');
5 |
6 | /*global toString:true*/
7 |
8 | // utils is a library of generic helper functions non-specific to axios
9 |
10 | var toString = Object.prototype.toString;
11 |
12 | /**
13 | * Determine if a value is an Array
14 | *
15 | * @param {Object} val The value to test
16 | * @returns {boolean} True if value is an Array, otherwise false
17 | */
18 | function isArray(val) {
19 | return toString.call(val) === '[object Array]';
20 | }
21 |
22 | /**
23 | * Determine if a value is an ArrayBuffer
24 | *
25 | * @param {Object} val The value to test
26 | * @returns {boolean} True if value is an ArrayBuffer, otherwise false
27 | */
28 | function isArrayBuffer(val) {
29 | return toString.call(val) === '[object ArrayBuffer]';
30 | }
31 |
32 | /**
33 | * Determine if a value is a FormData
34 | *
35 | * @param {Object} val The value to test
36 | * @returns {boolean} True if value is an FormData, otherwise false
37 | */
38 | function isFormData(val) {
39 | return (typeof FormData !== 'undefined') && (val instanceof FormData);
40 | }
41 |
42 | /**
43 | * Determine if a value is a view on an ArrayBuffer
44 | *
45 | * @param {Object} val The value to test
46 | * @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false
47 | */
48 | function isArrayBufferView(val) {
49 | var result;
50 | if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
51 | result = ArrayBuffer.isView(val);
52 | } else {
53 | result = (val) && (val.buffer) && (val.buffer instanceof ArrayBuffer);
54 | }
55 | return result;
56 | }
57 |
58 | /**
59 | * Determine if a value is a String
60 | *
61 | * @param {Object} val The value to test
62 | * @returns {boolean} True if value is a String, otherwise false
63 | */
64 | function isString(val) {
65 | return typeof val === 'string';
66 | }
67 |
68 | /**
69 | * Determine if a value is a Number
70 | *
71 | * @param {Object} val The value to test
72 | * @returns {boolean} True if value is a Number, otherwise false
73 | */
74 | function isNumber(val) {
75 | return typeof val === 'number';
76 | }
77 |
78 | /**
79 | * Determine if a value is undefined
80 | *
81 | * @param {Object} val The value to test
82 | * @returns {boolean} True if the value is undefined, otherwise false
83 | */
84 | function isUndefined(val) {
85 | return typeof val === 'undefined';
86 | }
87 |
88 | /**
89 | * Determine if a value is an Object
90 | *
91 | * @param {Object} val The value to test
92 | * @returns {boolean} True if value is an Object, otherwise false
93 | */
94 | function isObject(val) {
95 | return val !== null && typeof val === 'object';
96 | }
97 |
98 | /**
99 | * Determine if a value is a Date
100 | *
101 | * @param {Object} val The value to test
102 | * @returns {boolean} True if value is a Date, otherwise false
103 | */
104 | function isDate(val) {
105 | return toString.call(val) === '[object Date]';
106 | }
107 |
108 | /**
109 | * Determine if a value is a File
110 | *
111 | * @param {Object} val The value to test
112 | * @returns {boolean} True if value is a File, otherwise false
113 | */
114 | function isFile(val) {
115 | return toString.call(val) === '[object File]';
116 | }
117 |
118 | /**
119 | * Determine if a value is a Blob
120 | *
121 | * @param {Object} val The value to test
122 | * @returns {boolean} True if value is a Blob, otherwise false
123 | */
124 | function isBlob(val) {
125 | return toString.call(val) === '[object Blob]';
126 | }
127 |
128 | /**
129 | * Determine if a value is a Function
130 | *
131 | * @param {Object} val The value to test
132 | * @returns {boolean} True if value is a Function, otherwise false
133 | */
134 | function isFunction(val) {
135 | return toString.call(val) === '[object Function]';
136 | }
137 |
138 | /**
139 | * Determine if a value is a Stream
140 | *
141 | * @param {Object} val The value to test
142 | * @returns {boolean} True if value is a Stream, otherwise false
143 | */
144 | function isStream(val) {
145 | return isObject(val) && isFunction(val.pipe);
146 | }
147 |
148 | /**
149 | * Determine if a value is a URLSearchParams object
150 | *
151 | * @param {Object} val The value to test
152 | * @returns {boolean} True if value is a URLSearchParams object, otherwise false
153 | */
154 | function isURLSearchParams(val) {
155 | return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams;
156 | }
157 |
158 | /**
159 | * Trim excess whitespace off the beginning and end of a string
160 | *
161 | * @param {String} str The String to trim
162 | * @returns {String} The String freed of excess whitespace
163 | */
164 | function trim(str) {
165 | return str.replace(/^\s*/, '').replace(/\s*$/, '');
166 | }
167 |
168 | /**
169 | * Determine if we're running in a standard browser environment
170 | *
171 | * This allows axios to run in a web worker, and react-native.
172 | * Both environments support XMLHttpRequest, but not fully standard globals.
173 | *
174 | * web workers:
175 | * typeof window -> undefined
176 | * typeof document -> undefined
177 | *
178 | * react-native:
179 | * navigator.product -> 'ReactNative'
180 | */
181 | function isStandardBrowserEnv() {
182 | if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
183 | return false;
184 | }
185 | return (
186 | typeof window !== 'undefined' &&
187 | typeof document !== 'undefined'
188 | );
189 | }
190 |
191 | /**
192 | * Iterate over an Array or an Object invoking a function for each item.
193 | *
194 | * If `obj` is an Array callback will be called passing
195 | * the value, index, and complete array for each item.
196 | *
197 | * If 'obj' is an Object callback will be called passing
198 | * the value, key, and complete object for each property.
199 | *
200 | * @param {Object|Array} obj The object to iterate
201 | * @param {Function} fn The callback to invoke for each item
202 | */
203 | function forEach(obj, fn) {
204 | // Don't bother if no value provided
205 | if (obj === null || typeof obj === 'undefined') {
206 | return;
207 | }
208 |
209 | // Force an array if not already something iterable
210 | if (typeof obj !== 'object') {
211 | /*eslint no-param-reassign:0*/
212 | obj = [obj];
213 | }
214 |
215 | if (isArray(obj)) {
216 | // Iterate over array values
217 | for (var i = 0, l = obj.length; i < l; i++) {
218 | fn.call(null, obj[i], i, obj);
219 | }
220 | } else {
221 | // Iterate over object keys
222 | for (var key in obj) {
223 | if (Object.prototype.hasOwnProperty.call(obj, key)) {
224 | fn.call(null, obj[key], key, obj);
225 | }
226 | }
227 | }
228 | }
229 |
230 | /**
231 | * Accepts varargs expecting each argument to be an object, then
232 | * immutably merges the properties of each object and returns result.
233 | *
234 | * When multiple objects contain the same key the later object in
235 | * the arguments list will take precedence.
236 | *
237 | * Example:
238 | *
239 | * ```js
240 | * var result = merge({foo: 123}, {foo: 456});
241 | * console.log(result.foo); // outputs 456
242 | * ```
243 | *
244 | * @param {Object} obj1 Object to merge
245 | * @returns {Object} Result of all merge properties
246 | */
247 | function merge(/* obj1, obj2, obj3, ... */) {
248 | var result = {};
249 | function assignValue(val, key) {
250 | if (typeof result[key] === 'object' && typeof val === 'object') {
251 | result[key] = merge(result[key], val);
252 | } else {
253 | result[key] = val;
254 | }
255 | }
256 |
257 | for (var i = 0, l = arguments.length; i < l; i++) {
258 | forEach(arguments[i], assignValue);
259 | }
260 | return result;
261 | }
262 |
263 | /**
264 | * Extends object a by mutably adding to it the properties of object b.
265 | *
266 | * @param {Object} a The object to be extended
267 | * @param {Object} b The object to copy properties from
268 | * @param {Object} thisArg The object to bind function to
269 | * @return {Object} The resulting value of object a
270 | */
271 | function extend(a, b, thisArg) {
272 | forEach(b, function assignValue(val, key) {
273 | if (thisArg && typeof val === 'function') {
274 | a[key] = bind(val, thisArg);
275 | } else {
276 | a[key] = val;
277 | }
278 | });
279 | return a;
280 | }
281 |
282 | module.exports = {
283 | isArray: isArray,
284 | isArrayBuffer: isArrayBuffer,
285 | isBuffer: isBuffer,
286 | isFormData: isFormData,
287 | isArrayBufferView: isArrayBufferView,
288 | isString: isString,
289 | isNumber: isNumber,
290 | isObject: isObject,
291 | isUndefined: isUndefined,
292 | isDate: isDate,
293 | isFile: isFile,
294 | isBlob: isBlob,
295 | isFunction: isFunction,
296 | isStream: isStream,
297 | isURLSearchParams: isURLSearchParams,
298 | isStandardBrowserEnv: isStandardBrowserEnv,
299 | forEach: forEach,
300 | merge: merge,
301 | extend: extend,
302 | trim: trim
303 | };
304 |
--------------------------------------------------------------------------------
/test/specs/requests.spec.js:
--------------------------------------------------------------------------------
1 | describe('requests', function () {
2 | beforeEach(function () {
3 | jasmine.Ajax.install();
4 | });
5 |
6 | afterEach(function () {
7 | jasmine.Ajax.uninstall();
8 | });
9 |
10 | it('should treat single string arg as url', function (done) {
11 | axios('/foo');
12 |
13 | getAjaxRequest().then(function (request) {
14 | expect(request.url).toBe('/foo');
15 | expect(request.method).toBe('GET');
16 | done();
17 | });
18 | });
19 |
20 | it('should treat method value as lowercase string', function (done) {
21 | axios({
22 | url: '/foo',
23 | method: 'POST'
24 | }).then(function (response) {
25 | expect(response.config.method).toBe('post');
26 | done();
27 | });
28 |
29 | getAjaxRequest().then(function (request) {
30 | request.respondWith({
31 | status: 200
32 | });
33 | });
34 | });
35 |
36 | it('should allow string arg as url, and config arg', function (done) {
37 | axios.post('/foo');
38 |
39 | getAjaxRequest().then(function (request) {
40 | expect(request.url).toBe('/foo');
41 | expect(request.method).toBe('POST');
42 | done();
43 | });
44 | });
45 |
46 | it('should make an http request', function (done) {
47 | axios('/foo');
48 |
49 | getAjaxRequest().then(function (request) {
50 | expect(request.url).toBe('/foo');
51 | done();
52 | });
53 | });
54 |
55 | it('should reject on network errors', function (done) {
56 | // disable jasmine.Ajax since we're hitting a non-existant server anyway
57 | jasmine.Ajax.uninstall();
58 |
59 | var resolveSpy = jasmine.createSpy('resolve');
60 | var rejectSpy = jasmine.createSpy('reject');
61 |
62 | var finish = function () {
63 | expect(resolveSpy).not.toHaveBeenCalled();
64 | expect(rejectSpy).toHaveBeenCalled();
65 | var reason = rejectSpy.calls.first().args[0];
66 | expect(reason instanceof Error).toBe(true);
67 | expect(reason.config.method).toBe('get');
68 | expect(reason.config.url).toBe('http://thisisnotaserver/foo');
69 | expect(reason.request).toEqual(jasmine.any(XMLHttpRequest));
70 |
71 | // re-enable jasmine.Ajax
72 | jasmine.Ajax.install();
73 |
74 | done();
75 | };
76 |
77 | axios('http://thisisnotaserver/foo')
78 | .then(resolveSpy, rejectSpy)
79 | .then(finish, finish);
80 | });
81 |
82 | it('should reject when validateStatus returns false', function (done) {
83 | var resolveSpy = jasmine.createSpy('resolve');
84 | var rejectSpy = jasmine.createSpy('reject');
85 |
86 | axios('/foo', {
87 | validateStatus: function (status) {
88 | return status !== 500;
89 | }
90 | }).then(resolveSpy)
91 | .catch(rejectSpy)
92 | .then(function () {
93 | expect(resolveSpy).not.toHaveBeenCalled();
94 | expect(rejectSpy).toHaveBeenCalled();
95 | var reason = rejectSpy.calls.first().args[0];
96 | expect(reason instanceof Error).toBe(true);
97 | expect(reason.message).toBe('Request failed with status code 500');
98 | expect(reason.config.method).toBe('get');
99 | expect(reason.config.url).toBe('/foo');
100 | expect(reason.response.status).toBe(500);
101 |
102 | done();
103 | });
104 |
105 | getAjaxRequest().then(function (request) {
106 | request.respondWith({
107 | status: 500
108 | });
109 | });
110 | });
111 |
112 | it('should resolve when validateStatus returns true', function (done) {
113 | var resolveSpy = jasmine.createSpy('resolve');
114 | var rejectSpy = jasmine.createSpy('reject');
115 |
116 | axios('/foo', {
117 | validateStatus: function (status) {
118 | return status === 500;
119 | }
120 | }).then(resolveSpy)
121 | .catch(rejectSpy)
122 | .then(function () {
123 | expect(resolveSpy).toHaveBeenCalled();
124 | expect(rejectSpy).not.toHaveBeenCalled();
125 | done();
126 | });
127 |
128 | getAjaxRequest().then(function (request) {
129 | request.respondWith({
130 | status: 500
131 | });
132 | });
133 | });
134 |
135 | // https://github.com/axios/axios/issues/378
136 | it('should return JSON when rejecting', function (done) {
137 | var response;
138 |
139 | axios('/api/account/signup', {
140 | username: null,
141 | password: null
142 | }, {
143 | method: 'post',
144 | headers: {
145 | 'Accept': 'application/json'
146 | }
147 | })
148 | .catch(function (error) {
149 | response = error.response;
150 | });
151 |
152 | getAjaxRequest().then(function (request) {
153 | request.respondWith({
154 | status: 400,
155 | statusText: 'Bad Request',
156 | responseText: '{"error": "BAD USERNAME", "code": 1}'
157 | });
158 |
159 | setTimeout(function () {
160 | expect(typeof response.data).toEqual('object');
161 | expect(response.data.error).toEqual('BAD USERNAME');
162 | expect(response.data.code).toEqual(1);
163 | done();
164 | }, 100);
165 | });
166 | });
167 |
168 | it('should make cross domian http request', function (done) {
169 | var response;
170 |
171 | axios.post('www.someurl.com/foo').then(function(res){
172 | response = res;
173 | });
174 |
175 | getAjaxRequest().then(function (request) {
176 | request.respondWith({
177 | status: 200,
178 | statusText: 'OK',
179 | responseText: '{"foo": "bar"}',
180 | headers: {
181 | 'Content-Type': 'application/json'
182 | }
183 | });
184 |
185 | setTimeout(function () {
186 | expect(response.data.foo).toEqual('bar');
187 | expect(response.status).toEqual(200);
188 | expect(response.statusText).toEqual('OK');
189 | expect(response.headers['content-type']).toEqual('application/json');
190 | done();
191 | }, 100);
192 | });
193 | });
194 |
195 |
196 | it('should supply correct response', function (done) {
197 | var response;
198 |
199 | axios.post('/foo').then(function (res) {
200 | response = res;
201 | });
202 |
203 | getAjaxRequest().then(function (request) {
204 | request.respondWith({
205 | status: 200,
206 | statusText: 'OK',
207 | responseText: '{"foo": "bar"}',
208 | headers: {
209 | 'Content-Type': 'application/json'
210 | }
211 | });
212 |
213 | setTimeout(function () {
214 | expect(response.data.foo).toEqual('bar');
215 | expect(response.status).toEqual(200);
216 | expect(response.statusText).toEqual('OK');
217 | expect(response.headers['content-type']).toEqual('application/json');
218 | done();
219 | }, 100);
220 | });
221 | });
222 |
223 | // https://github.com/axios/axios/issues/201
224 | it('should fix IE no content error', function (done) {
225 | var response;
226 |
227 | axios('/foo').then(function (res) {
228 | response = res
229 | });
230 |
231 | getAjaxRequest().then(function (request) {
232 | request.respondWith({
233 | status: 1223,
234 | statusText: 'Unknown'
235 | });
236 |
237 | setTimeout(function () {
238 | expect(response.status).toEqual(204);
239 | expect(response.statusText).toEqual('No Content');
240 | done();
241 | }, 100);
242 | });
243 | });
244 |
245 | it('should allow overriding Content-Type header case-insensitive', function (done) {
246 | var response;
247 | var contentType = 'application/vnd.myapp.type+json';
248 |
249 | axios.post('/foo', { prop: 'value' }, {
250 | headers: {
251 | 'content-type': contentType
252 | }
253 | }).then(function (res) {
254 | response = res;
255 | });
256 |
257 | getAjaxRequest().then(function (request) {
258 | expect(request.requestHeaders['Content-Type']).toEqual(contentType);
259 | done();
260 | });
261 | });
262 |
263 | it('should support binary data as array buffer', function (done) {
264 | // Int8Array doesn't exist in IE8/9
265 | if (isOldIE && typeof Int8Array === 'undefined') {
266 | done();
267 | return;
268 | }
269 |
270 | var input = new Int8Array(2);
271 | input[0] = 1;
272 | input[1] = 2;
273 |
274 | axios.post('/foo', input.buffer);
275 |
276 | getAjaxRequest().then(function (request) {
277 | var output = new Int8Array(request.params);
278 | expect(output.length).toEqual(2);
279 | expect(output[0]).toEqual(1);
280 | expect(output[1]).toEqual(2);
281 | done();
282 | });
283 | });
284 |
285 | it('should support binary data as array buffer view', function (done) {
286 | // Int8Array doesn't exist in IE8/9
287 | if (isOldIE && typeof Int8Array === 'undefined') {
288 | done();
289 | return;
290 | }
291 |
292 | var input = new Int8Array(2);
293 | input[0] = 1;
294 | input[1] = 2;
295 |
296 | axios.post('/foo', input);
297 |
298 | getAjaxRequest().then(function (request) {
299 | var output = new Int8Array(request.params);
300 | expect(output.length).toEqual(2);
301 | expect(output[0]).toEqual(1);
302 | expect(output[1]).toEqual(2);
303 | done();
304 | });
305 | });
306 |
307 | it('should support array buffer response', function (done) {
308 | // ArrayBuffer doesn't exist in IE8/9
309 | if (isOldIE && typeof ArrayBuffer === 'undefined') {
310 | done();
311 | return;
312 | }
313 |
314 | var response;
315 |
316 | function str2ab(str) {
317 | var buff = new ArrayBuffer(str.length * 2);
318 | var view = new Uint16Array(buff);
319 | for ( var i=0, l=str.length; i