metal-ajax
Advanced tools
Comparing version 3.1.0 to 3.1.1
@@ -21,2 +21,5 @@ 'use strict'; | ||
/** | ||
* Ajax class | ||
*/ | ||
var Ajax = function () { | ||
@@ -30,3 +33,2 @@ function Ajax() { | ||
/** | ||
@@ -66,7 +68,7 @@ * XmlHttpRequest's getAllResponseHeaders() method returns a string of | ||
* @param {?string} body | ||
* @param {MultiMap=} opt_headers | ||
* @param {MultiMap=} opt_params | ||
* @param {number=} opt_timeout | ||
* @param {boolean=} opt_sync | ||
* @param {boolean=} opt_withCredentials | ||
* @param {MultiMap=} headers | ||
* @param {MultiMap=} params | ||
* @param {number=} timeout | ||
* @param {boolean=} sync | ||
* @param {boolean=} withCredentials | ||
* @return {Promise} Deferred ajax request. | ||
@@ -78,3 +80,3 @@ * @protected | ||
key: 'request', | ||
value: function request(url, method, body, opt_headers, opt_params, opt_timeout, opt_sync, opt_withCredentials) { | ||
value: function request(url, method, body, headers, params, timeout, sync, withCredentials) { | ||
url = url || ''; | ||
@@ -118,3 +120,3 @@ method = method || 'GET'; | ||
}).thenAlways(function () { | ||
clearTimeout(timeout); | ||
clearTimeout(reqTimeout); | ||
}); | ||
@@ -124,4 +126,4 @@ | ||
if (opt_params) { | ||
url.addParametersFromMultiMap(opt_params).toString(); | ||
if (params) { | ||
url.addParametersFromMultiMap(params).toString(); | ||
} | ||
@@ -131,11 +133,11 @@ | ||
request.open(method, url, !opt_sync); | ||
request.open(method, url, !sync); | ||
if (opt_withCredentials) { | ||
if (withCredentials) { | ||
request.withCredentials = true; | ||
} | ||
if (opt_headers) { | ||
opt_headers.names().forEach(function (name) { | ||
request.setRequestHeader(name, opt_headers.getAll(name).join(', ')); | ||
if (headers) { | ||
headers.names().forEach(function (name) { | ||
request.setRequestHeader(name, headers.getAll(name).join(', ')); | ||
}); | ||
@@ -146,6 +148,8 @@ } | ||
if ((0, _metal.isDefAndNotNull)(opt_timeout)) { | ||
var timeout = setTimeout(function () { | ||
var reqTimeout = void 0; | ||
if ((0, _metal.isDefAndNotNull)(timeout)) { | ||
reqTimeout = setTimeout(function () { | ||
promise.cancel('Request timeout'); | ||
}, opt_timeout); | ||
}, timeout); | ||
} | ||
@@ -152,0 +156,0 @@ |
{ | ||
"name": "metal-ajax", | ||
"version": "3.1.0", | ||
"version": "3.1.1", | ||
"description": "Metal.js utility to perform Ajax requests", | ||
"license": "BSD", | ||
"repository": "metal/metal-ajax", | ||
"repository": "https://github.com/metal/metal-plugins/tree/master/packages/metal-ajax", | ||
"engines": { | ||
@@ -19,5 +19,10 @@ "node": ">=0.12.0", | ||
"scripts": { | ||
"compile": "babel --presets metal -d lib/ src/", | ||
"checkFormat": "npm run prettier -- --list-different", | ||
"compile": "babel --presets env -d lib/ src/", | ||
"format": "npm run prettier -- --write", | ||
"lint": "eslint '{src,test}/**/*.js'", | ||
"prepublish": "npm run compile", | ||
"test": "gulp test" | ||
"prettier": "prettier-eslint '{src,test}/**/*.js'", | ||
"test": "karma start", | ||
"test:saucelabs": "karma start karma-saucelabs.conf.js" | ||
}, | ||
@@ -29,18 +34,27 @@ "keywords": [ | ||
"metal": "^2.0.0", | ||
"metal-promise": "^3.0.3", | ||
"metal-uri": "^3.0.0" | ||
"metal-promise": "^3.0.4", | ||
"metal-uri": "^3.1.1" | ||
}, | ||
"devDependencies": { | ||
"babel-cli": "^6.26.0", | ||
"babel-core": "^6.26.0", | ||
"babel-loader": "^7.1.2", | ||
"babel-preset-env": "^1.6.1", | ||
"babel-preset-metal": "^4.1.0", | ||
"babelify": "^7.3.0", | ||
"browserify": "^14.5.0", | ||
"gulp": "^3.9.1", | ||
"gulp-metal": "^2.2.2", | ||
"karma": "^1.7.1", | ||
"karma-browserify": "^5.1.1", | ||
"chai": "^4.1.2", | ||
"eslint": "^4.11.0", | ||
"eslint-config-liferay": "^2.0.16", | ||
"karma": "^1.1.0", | ||
"karma-chai": "^0.1.0", | ||
"karma-chrome-launcher": "^2.2.0", | ||
"karma-mocha": "^1.3.0", | ||
"karma-sauce-launcher": "~1.1.0", | ||
"karma-sinon": "^1.0.5", | ||
"karma-webpack": "^2.0.6", | ||
"metal-structs": "^1.0.0", | ||
"metal-useragent": "^2.1.3" | ||
"metal-useragent": "^2.1.3", | ||
"mocha": "^4.0.1", | ||
"prettier-eslint-cli": "^4.4.0", | ||
"sinon": "^4.1.2", | ||
"webpack": "^3.8.1" | ||
} | ||
} |
@@ -7,19 +7,95 @@ # metal-ajax | ||
Metal.js utility to perform Ajax requests | ||
Low-level Metal.js utility to perform Ajax requests. If you're looking for | ||
something higher level, take a look | ||
at [fetch](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch). | ||
## Use | ||
### Simple request | ||
```javascript | ||
import Ajax from 'metal-ajax'; | ||
Ajax.request('/url', 'get') | ||
.then(xhrResponse => { | ||
// Handle response | ||
}); | ||
``` | ||
### Posts | ||
```javascript | ||
Ajax.request('/url', 'post', 'requestBody') | ||
.then(xhrResponse => { | ||
// Handle response | ||
}); | ||
``` | ||
### Request headers and params | ||
Custom request headers and params can bet set | ||
using a `MultiMap` from [metal-structs](https://github.com/metal/metal-structs). | ||
```javascript | ||
import {MultiMap} from 'metal-structs'; | ||
const headers = new MultiMap(); | ||
const params = new MultiMap(); | ||
headers.add('content-type', 'application/json'); | ||
params.add('foo', 'bar'); | ||
Ajax.request('/url', 'get', null, headers, params) | ||
.then(function(xhrResponse) { | ||
// Handle response | ||
}); | ||
``` | ||
### Catching errors | ||
```javascript | ||
Ajax.request('/url', 'get') | ||
.then(xhrResponse => { | ||
// Handle response | ||
}) | ||
.catch(error => { | ||
// Handle error | ||
}); | ||
``` | ||
### Watch for progress | ||
In order for the `progress` listener to work, the response _must_ have | ||
the [Content-Length](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length) response | ||
header set. | ||
```javascript | ||
Ajax.request('/url', 'get') | ||
.progress(progress => { | ||
// Fires with a value between 0 and 1 representing the percent | ||
}) | ||
.then(xhrResponse => { | ||
// Handle response | ||
}) | ||
``` | ||
## Setup | ||
1. Install NodeJS >= [v0.12.0](http://nodejs.org/dist/v0.12.0/), if you don't have it yet. | ||
1. Install a recent release of [NodeJS](https://nodejs.org/en/download/) if you | ||
don't have it yet. | ||
2. Install global dependencies: | ||
2. Install local dependencies: | ||
``` | ||
[sudo] npm install -g gulp | ||
npm install | ||
``` | ||
3. Install local dependencies: | ||
3. Run the tests: | ||
``` | ||
npm install | ||
npm test | ||
``` | ||
## Contributing | ||
Check out the [contributing guidelines](https://github.com/metal/metal-plugins/blob/master/CONTRIBUTING.md) for more information. |
'use strict'; | ||
import { isDef, isDefAndNotNull } from 'metal'; | ||
import {isDef, isDefAndNotNull} from 'metal'; | ||
import Uri from 'metal-uri'; | ||
import { ProgressPromise as Promise } from 'metal-promise'; | ||
import {ProgressPromise as Promise} from 'metal-promise'; | ||
/** | ||
* Ajax class | ||
*/ | ||
class Ajax { | ||
/** | ||
@@ -19,15 +21,15 @@ * XmlHttpRequest's getAllResponseHeaders() method returns a string of | ||
static parseResponseHeaders(allHeaders) { | ||
var headers = []; | ||
let headers = []; | ||
if (!allHeaders) { | ||
return headers; | ||
} | ||
var pairs = allHeaders.split('\u000d\u000a'); | ||
for (var i = 0; i < pairs.length; i++) { | ||
var index = pairs[i].indexOf('\u003a\u0020'); | ||
let pairs = allHeaders.split('\u000d\u000a'); | ||
for (let i = 0; i < pairs.length; i++) { | ||
let index = pairs[i].indexOf('\u003a\u0020'); | ||
if (index > 0) { | ||
var name = pairs[i].substring(0, index); | ||
var value = pairs[i].substring(index + 2); | ||
let name = pairs[i].substring(0, index); | ||
let value = pairs[i].substring(index + 2); | ||
headers.push({ | ||
name: name, | ||
value: value | ||
value: value, | ||
}); | ||
@@ -44,18 +46,27 @@ } | ||
* @param {?string} body | ||
* @param {MultiMap=} opt_headers | ||
* @param {MultiMap=} opt_params | ||
* @param {number=} opt_timeout | ||
* @param {boolean=} opt_sync | ||
* @param {boolean=} opt_withCredentials | ||
* @param {MultiMap=} headers | ||
* @param {MultiMap=} params | ||
* @param {number=} timeout | ||
* @param {boolean=} sync | ||
* @param {boolean=} withCredentials | ||
* @return {Promise} Deferred ajax request. | ||
* @protected | ||
*/ | ||
static request(url, method, body, opt_headers, opt_params, opt_timeout, opt_sync, opt_withCredentials) { | ||
static request( | ||
url, | ||
method, | ||
body, | ||
headers, | ||
params, | ||
timeout, | ||
sync, | ||
withCredentials | ||
) { | ||
url = url || ''; | ||
method = method || 'GET'; | ||
var request = new XMLHttpRequest(); | ||
var previousReadyState = 0; | ||
let request = new XMLHttpRequest(); | ||
let previousReadyState = 0; | ||
var promise = new Promise(function(resolve, reject, progress) { | ||
let promise = new Promise(function(resolve, reject, progress) { | ||
request.onload = function() { | ||
@@ -74,3 +85,7 @@ if (request.aborted) { | ||
request.onreadystatechange = function() { | ||
if (previousReadyState && previousReadyState < 3 && 4 === request.readyState) { | ||
if ( | ||
previousReadyState && | ||
previousReadyState < 3 && | ||
4 === request.readyState | ||
) { | ||
request.terminatedPrematurely = true; | ||
@@ -81,21 +96,23 @@ } | ||
request.onerror = function() { | ||
var message = 'Request error'; | ||
let message = 'Request error'; | ||
if (request.terminatedPrematurely) { | ||
message = 'Request terminated prematurely'; | ||
} | ||
var error = new Error(message); | ||
let error = new Error(message); | ||
error.request = request; | ||
reject(error); | ||
}; | ||
}).thenCatch(function(reason) { | ||
request.abort(); | ||
throw reason; | ||
}).thenAlways(function() { | ||
clearTimeout(timeout); | ||
}); | ||
}) | ||
.thenCatch(function(reason) { | ||
request.abort(); | ||
throw reason; | ||
}) | ||
.thenAlways(function() { | ||
clearTimeout(reqTimeout); | ||
}); | ||
url = new Uri(url); | ||
if (opt_params) { | ||
url.addParametersFromMultiMap(opt_params).toString(); | ||
if (params) { | ||
url.addParametersFromMultiMap(params).toString(); | ||
} | ||
@@ -105,11 +122,11 @@ | ||
request.open(method, url, !opt_sync); | ||
request.open(method, url, !sync); | ||
if (opt_withCredentials) { | ||
if (withCredentials) { | ||
request.withCredentials = true; | ||
} | ||
if (opt_headers) { | ||
opt_headers.names().forEach(function(name) { | ||
request.setRequestHeader(name, opt_headers.getAll(name).join(', ')); | ||
if (headers) { | ||
headers.names().forEach(function(name) { | ||
request.setRequestHeader(name, headers.getAll(name).join(', ')); | ||
}); | ||
@@ -120,6 +137,8 @@ } | ||
if (isDefAndNotNull(opt_timeout)) { | ||
var timeout = setTimeout(function() { | ||
let reqTimeout; | ||
if (isDefAndNotNull(timeout)) { | ||
reqTimeout = setTimeout(function() { | ||
promise.cancel('Request timeout'); | ||
}, opt_timeout); | ||
}, timeout); | ||
} | ||
@@ -129,5 +148,4 @@ | ||
} | ||
} | ||
export default Ajax; |
183
test/Ajax.js
@@ -5,32 +5,34 @@ 'use strict'; | ||
import UA from 'metal-useragent'; | ||
import { MultiMap } from 'metal-structs'; | ||
import {MultiMap} from 'metal-structs'; | ||
describe('Ajax', function() { | ||
describe('Utils', function() { | ||
it('should parse response headers', function() { | ||
var headers = 'Name\u003a\u0020Value\u000d\u000aName\u003a\u0020Value'; | ||
assert.deepEqual([{ | ||
name: 'Name', | ||
value: 'Value' | ||
}, { | ||
name: 'Name', | ||
value: 'Value' | ||
}], Ajax.parseResponseHeaders(headers)); | ||
let headers = 'Name\u003a\u0020Value\u000d\u000aName\u003a\u0020Value'; | ||
assert.deepEqual( | ||
[ | ||
{ | ||
name: 'Name', | ||
value: 'Value', | ||
}, | ||
{ | ||
name: 'Name', | ||
value: 'Value', | ||
}, | ||
], | ||
Ajax.parseResponseHeaders(headers) | ||
); | ||
}); | ||
it('should return empty array when parsing empty response headers', function() { | ||
var headers = ''; | ||
let headers = ''; | ||
assert.deepEqual([], Ajax.parseResponseHeaders(headers)); | ||
}); | ||
}); | ||
describe('Request', function() { | ||
beforeEach(function() { | ||
this.xhr = sinon.useFakeXMLHttpRequest(); | ||
var requests = this.requests = []; | ||
let requests = (this.requests = []); | ||
@@ -64,3 +66,3 @@ this.xhr.onCreate = function(xhr) { | ||
it('should cancel send request to an url', function(done) { | ||
var self = this; | ||
let self = this; | ||
Ajax.request('/url') | ||
@@ -79,7 +81,15 @@ .then(function() { | ||
let withCredentials = true; | ||
Ajax.request('/url', 'POST', null, null, null, null, false, withCredentials) | ||
.then(function(xhrResponse) { | ||
assert.ok(xhrResponse.withCredentials); | ||
done(); | ||
}); | ||
Ajax.request( | ||
'/url', | ||
'POST', | ||
null, | ||
null, | ||
null, | ||
null, | ||
false, | ||
withCredentials | ||
).then(function(xhrResponse) { | ||
assert.ok(xhrResponse.withCredentials); | ||
done(); | ||
}); | ||
this.requests[0].respond(200); | ||
@@ -90,7 +100,15 @@ }); | ||
let withCredentials = false; | ||
Ajax.request('/url', 'POST', null, null, null, null, false, withCredentials) | ||
.then(function(xhrResponse) { | ||
assert.notOk(xhrResponse.withCredentials); | ||
done(); | ||
}); | ||
Ajax.request( | ||
'/url', | ||
'POST', | ||
null, | ||
null, | ||
null, | ||
null, | ||
false, | ||
withCredentials | ||
).then(function(xhrResponse) { | ||
assert.notOk(xhrResponse.withCredentials); | ||
done(); | ||
}); | ||
this.requests[0].respond(200); | ||
@@ -100,7 +118,6 @@ }); | ||
it('should send request with different http method', function(done) { | ||
Ajax.request('/url', 'POST') | ||
.then(function(xhrResponse) { | ||
assert.strictEqual('POST', xhrResponse.method); | ||
done(); | ||
}); | ||
Ajax.request('/url', 'POST').then(function(xhrResponse) { | ||
assert.strictEqual('POST', xhrResponse.method); | ||
done(); | ||
}); | ||
this.requests[0].respond(200); | ||
@@ -110,8 +127,7 @@ }); | ||
it('should send request with body', function(done) { | ||
Ajax.request('/url', 'post', 'requestBody') | ||
.then(function(xhrResponse) { | ||
assert.strictEqual('requestBody', xhrResponse.requestBody); | ||
assert.strictEqual('responseBody', xhrResponse.response); | ||
done(); | ||
}); | ||
Ajax.request('/url', 'post', 'requestBody').then(function(xhrResponse) { | ||
assert.strictEqual('requestBody', xhrResponse.requestBody); | ||
assert.strictEqual('responseBody', xhrResponse.response); | ||
done(); | ||
}); | ||
this.requests[0].respond(200, null, 'responseBody'); | ||
@@ -121,25 +137,31 @@ }); | ||
it('should send request with header', function(done) { | ||
var headers = new MultiMap(); | ||
let headers = new MultiMap(); | ||
headers.add('content-type', 'application/json'); | ||
Ajax.request('/url', 'get', null, headers) | ||
.then(function(xhrResponse) { | ||
assert.deepEqual({ | ||
'content-type': 'application/json' | ||
}, xhrResponse.requestHeaders); | ||
done(); | ||
}); | ||
Ajax.request('/url', 'get', null, headers).then(function(xhrResponse) { | ||
assert.deepEqual( | ||
{ | ||
'content-type': 'application/json;charset=utf-8', | ||
}, | ||
xhrResponse.requestHeaders | ||
); | ||
done(); | ||
}); | ||
this.requests[0].respond(200); | ||
}); | ||
it('should send request with multiple headers with same name', function(done) { | ||
var headers = new MultiMap(); | ||
it('should send request with multiple headers with same name', function( | ||
done | ||
) { | ||
let headers = new MultiMap(); | ||
headers.add('content-type', 'application/json'); | ||
headers.add('content-type', 'text/html'); | ||
Ajax.request('/url', 'get', null, headers) | ||
.then(function(xhrResponse) { | ||
assert.deepEqual({ | ||
'content-type': 'application/json, text/html' | ||
}, xhrResponse.requestHeaders); | ||
done(); | ||
}); | ||
Ajax.request('/url', 'get', null, headers).then(function(xhrResponse) { | ||
assert.deepEqual( | ||
{ | ||
'content-type': 'application/json, text/html;charset=utf-8', | ||
}, | ||
xhrResponse.requestHeaders | ||
); | ||
done(); | ||
}); | ||
this.requests[0].respond(200); | ||
@@ -149,11 +171,13 @@ }); | ||
it('should response with headers', function(done) { | ||
Ajax.request('/url') | ||
.then(function(xhrResponse) { | ||
assert.deepEqual({ | ||
'content-type': 'application/json' | ||
}, xhrResponse.responseHeaders); | ||
done(); | ||
}); | ||
Ajax.request('/url').then(function(xhrResponse) { | ||
assert.deepEqual( | ||
{ | ||
'content-type': 'application/json', | ||
}, | ||
xhrResponse.responseHeaders | ||
); | ||
done(); | ||
}); | ||
this.requests[0].respond(200, { | ||
'content-type': 'application/json' | ||
'content-type': 'application/json', | ||
}); | ||
@@ -171,10 +195,11 @@ }); | ||
it('should parse request query string', function(done) { | ||
var params = new MultiMap(); | ||
let params = new MultiMap(); | ||
params.add('query', 1); | ||
params.add('query', ' '); | ||
Ajax.request('/url?foo=1', 'get', null, null, params, null, false) | ||
.then(function(xhrResponse) { | ||
Ajax.request('/url?foo=1', 'get', null, null, params, null, false).then( | ||
function(xhrResponse) { | ||
assert.strictEqual('/url?foo=1&query=1&query=%20', xhrResponse.url); | ||
done(); | ||
}); | ||
} | ||
); | ||
this.requests[0].respond(200); | ||
@@ -184,7 +209,8 @@ }); | ||
it('should parse request query string without params', function(done) { | ||
Ajax.request('/url?foo=1', 'get', null, null, null, null, false) | ||
.then(function(xhrResponse) { | ||
Ajax.request('/url?foo=1', 'get', null, null, null, null, false).then( | ||
function(xhrResponse) { | ||
assert.strictEqual('/url?foo=1', xhrResponse.url); | ||
done(); | ||
}); | ||
} | ||
); | ||
this.requests[0].respond(200); | ||
@@ -194,17 +220,16 @@ }); | ||
it('should cancel request if given timeout is reached', function(done) { | ||
Ajax.request('/url?foo=1', 'get', null, null, null, 100, false) | ||
.catch(function() { | ||
Ajax.request('/url?foo=1', 'get', null, null, null, 100, false).catch( | ||
function() { | ||
done(); | ||
}); | ||
} | ||
); | ||
}); | ||
it('should fail on request error', function(done) { | ||
Ajax.request('/url') | ||
.catch(function(reason) { | ||
assert.ok(reason instanceof Error); | ||
done(); | ||
}); | ||
Ajax.request('/url').catch(function(reason) { | ||
assert.ok(reason instanceof Error); | ||
done(); | ||
}); | ||
this.requests[0].error(); | ||
}); | ||
}); | ||
@@ -238,5 +263,3 @@ | ||
}); | ||
}); | ||
}); |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
334545
1571
101
20
Updatedmetal-promise@^3.0.4
Updatedmetal-uri@^3.1.1