From e253b0ef3ef17d900ec9d1814a4bba8e00c1c70b Mon Sep 17 00:00:00 2001 From: Nick Uraltsev Date: Sat, 21 Nov 2015 17:41:02 -0800 Subject: [PATCH 1/4] Add combineURLs helper --- lib/helpers/combineURLs.js | 12 ++++++++++++ test/specs/helpers/combineURLs.spec.js | 15 +++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 lib/helpers/combineURLs.js create mode 100644 test/specs/helpers/combineURLs.spec.js diff --git a/lib/helpers/combineURLs.js b/lib/helpers/combineURLs.js new file mode 100644 index 0000000..7145d10 --- /dev/null +++ b/lib/helpers/combineURLs.js @@ -0,0 +1,12 @@ +'use strict'; + +/** + * Creates a new URL by combining the specified URLs + * + * @param {string} baseURL The base URL + * @param {string} relativeURL The relative URL + * @returns {string} The combined URL + */ +module.exports = function combineURLs(baseURL, relativeURL) { + return baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, ''); +}; diff --git a/test/specs/helpers/combineURLs.spec.js b/test/specs/helpers/combineURLs.spec.js new file mode 100644 index 0000000..e09b730 --- /dev/null +++ b/test/specs/helpers/combineURLs.spec.js @@ -0,0 +1,15 @@ +var combineURLs = require('../../../lib/helpers/combineURLs'); + +describe('helpers::combineURLs', function () { + it('should combine URLs', function () { + expect(combineURLs('https://api.github.com', '/users')).toBe('https://api.github.com/users'); + }); + + it('should remove duplicate slashes', function () { + expect(combineURLs('https://api.github.com/', '/users')).toBe('https://api.github.com/users'); + }); + + it('should insert missing slash', function () { + expect(combineURLs('https://api.github.com', 'users')).toBe('https://api.github.com/users'); + }); +}); From 20a25a278373d2e7c19e3fc5b204cee7e42c4218 Mon Sep 17 00:00:00 2001 From: Nick Uraltsev Date: Sat, 21 Nov 2015 19:29:53 -0800 Subject: [PATCH 2/4] Add isAbsoluteURL helper --- lib/helpers/isAbsoluteURL.js | 14 ++++++++++++++ test/specs/helpers/isAbsoluteURL.spec.js | 23 +++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 lib/helpers/isAbsoluteURL.js create mode 100644 test/specs/helpers/isAbsoluteURL.spec.js diff --git a/lib/helpers/isAbsoluteURL.js b/lib/helpers/isAbsoluteURL.js new file mode 100644 index 0000000..d33e992 --- /dev/null +++ b/lib/helpers/isAbsoluteURL.js @@ -0,0 +1,14 @@ +'use strict'; + +/** + * Determines whether the specified URL is absolute + * + * @param {string} url The URL to test + * @returns {boolean} True if the specified URL is absolute, otherwise false + */ +module.exports = function isAbsoluteURL(url) { + // A URL is considered absolute if it begins with "://" or "//" (protocol-relative URL). + // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed + // by any combination of letters, digits, plus, period, or hyphen. + return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url); +}; diff --git a/test/specs/helpers/isAbsoluteURL.spec.js b/test/specs/helpers/isAbsoluteURL.spec.js new file mode 100644 index 0000000..0af4139 --- /dev/null +++ b/test/specs/helpers/isAbsoluteURL.spec.js @@ -0,0 +1,23 @@ +var isAbsoluteURL = require('../../../lib/helpers/isAbsoluteURL'); + +describe('helpers::isAbsoluteURL', function () { + it('should return true if URL begins with valid scheme name', function () { + expect(isAbsoluteURL('https://api.github.com/users')).toBe(true); + expect(isAbsoluteURL('custom-scheme-v1.0://example.com/')).toBe(true); + expect(isAbsoluteURL('HTTP://example.com/')).toBe(true); + }); + + it('should return false if URL begins with invalid scheme name', function () { + expect(isAbsoluteURL('123://example.com/')).toBe(false); + expect(isAbsoluteURL('!valid://example.com/')).toBe(false); + }); + + it('should return true if URL is protocol-relative', function () { + expect(isAbsoluteURL('//example.com/')).toBe(true); + }); + + it('should return false if URL is relative', function () { + expect(isAbsoluteURL('/foo')).toBe(false); + expect(isAbsoluteURL('foo')).toBe(false); + }); +}); From 435636c714954b5903c57dae1d7f983dd4585d60 Mon Sep 17 00:00:00 2001 From: Nick Uraltsev Date: Sat, 21 Nov 2015 23:51:59 -0800 Subject: [PATCH 3/4] Add support for baseURL parameter --- axios.d.ts | 1 + lib/axios.js | 6 ++++++ test/specs/options.spec.js | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/axios.d.ts b/axios.d.ts index fb4aaab..b8a3aad 100644 --- a/axios.d.ts +++ b/axios.d.ts @@ -49,6 +49,7 @@ declare module axios { xsrfCookieName?: string; xsrfHeaderName?: string; paramsSerializer?: (params: any) => string; + baseURL?: string; } interface RequestOptions extends InstanceOptions { diff --git a/lib/axios.js b/lib/axios.js index 29a5060..e75ce67 100644 --- a/lib/axios.js +++ b/lib/axios.js @@ -4,6 +4,8 @@ var defaults = require('./defaults'); var utils = require('./utils'); var dispatchRequest = require('./core/dispatchRequest'); var InterceptorManager = require('./core/InterceptorManager'); +var isAbsoluteURL = require('./helpers/isAbsoluteURL'); +var combineURLs = require('./helpers/combineURLs'); function Axios (defaultConfig) { this.defaultConfig = utils.merge({ @@ -29,6 +31,10 @@ Axios.prototype.request = function (config) { config = utils.merge(this.defaultConfig, { method: 'get' }, config); + if (config.baseURL && !isAbsoluteURL(config.url)) { + config.url = combineURLs(config.baseURL, config.url); + } + // Don't allow overriding defaults.withCredentials config.withCredentials = config.withCredentials || defaults.withCredentials; diff --git a/test/specs/options.spec.js b/test/specs/options.spec.js index a910662..312fd37 100644 --- a/test/specs/options.spec.js +++ b/test/specs/options.spec.js @@ -78,4 +78,42 @@ describe('options', function () { done(); }, 0); }); + + it('should accept base URL', function (done) { + var request; + + const instance = axios.create({ + baseURL: 'http://test.com/' + }); + + instance.request({ + url: '/foo' + }); + + setTimeout(function () { + request = jasmine.Ajax.requests.mostRecent(); + + expect(request.url).toBe('http://test.com/foo'); + done(); + }, 0); + }); + + it('should ignore base URL if request URL is absolute', function (done) { + var request; + + const instance = axios.create({ + baseURL: 'http://someurl.com/' + }); + + instance.request({ + url: 'http://someotherurl.com/' + }); + + setTimeout(function () { + request = jasmine.Ajax.requests.mostRecent(); + + expect(request.url).toBe('http://someotherurl.com/'); + done(); + }, 0); + }); }); From 2ab201f049357ea2cb3c8b4286795bafcbf3891b Mon Sep 17 00:00:00 2001 From: Nick Uraltsev Date: Sun, 22 Nov 2015 01:32:59 -0800 Subject: [PATCH 4/4] Update README.md: baseURL parameter --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 3cba598..c168286 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,7 @@ You can create a new instance of axios with a custom config. ```js var instance = axios.create({ + baseURL: 'https://some-domain.com/api/', timeout: 1000, headers: {'X-Custom-Header': 'foobar'} }); @@ -165,6 +166,11 @@ These are the available config options for making requests. Only the `url` is re { // `url` is the server URL that will be used for the request url: '/user', + + // `baseURL` will be prepended to `url` unless `url` is absolute. + // It can be convenient to set `baseURL` for an instance of axios to pass relative URLs + // to methods of that instance. + baseURL: 'https://some-domain.com/api/', // `method` is the request method to be used when making the request method: 'get', // default