Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ node_modules
lib/
/.idea
*.tgz
/.vscode
40 changes: 24 additions & 16 deletions src/Agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,24 @@ export default class Agent {
this.prefix = prefix(baseUrl);
}

get(uri, auth, query, context) {
return this.request({ uri, auth, method: 'get', query, context });
get(uri, auth, query, context, headers) {
return this.request({ uri, auth, method: 'get', query, context, headers });
}

head(uri, auth, query, context) {
return this.request({ uri, auth, method: 'head', query, context });
head(uri, auth, query, context, headers) {
return this.request({ uri, auth, method: 'head', query, context, headers });
}

post(uri, data, auth, context) {
return this.request({ uri, data, auth, method: 'post', context });
post(uri, data, auth, context, headers) {
return this.request({ uri, data, auth, method: 'post', context, headers });
}

put(uri, data, auth, context) {
return this.request({ uri, data, auth, method: 'put', context });
put(uri, data, auth, context, headers) {
return this.request({ uri, data, auth, method: 'put', context, headers });
}

delete(uri, data, auth, context) {
return this.request({ uri, data, auth, method: 'delete', context });
delete(uri, data, auth, context, headers) {
return this.request({ uri, data, auth, method: 'delete', context, headers });
}


Expand All @@ -56,7 +56,8 @@ export default class Agent {
* @param {String} query Query parameters
* @param {Object} form Form fields
* @param {Object} files array of file names and file content
* @parma {Object} context the invocation context, describing the tool and project.
* @param {Object} context the invocation context, describing the tool and project.
* @param {Object} headers request headers to set
* @return {Promise} A promise. fulfilled with {body, statusCode}, rejected with { statusCode, errorDescription, error, body }
*/
request({
Expand All @@ -68,10 +69,11 @@ export default class Agent {
form = undefined,
files = undefined,
context = undefined,
raw = false
raw = false,
headers = {}
}) {
const requestFiles = this._sanitizeFiles(files);
return this._request({ uri, method, data, auth, query, form, context, files: requestFiles, raw });
return this._request({ uri, method, data, auth, query, form, context, files: requestFiles, raw, headers });
}

/**
Expand All @@ -84,10 +86,11 @@ export default class Agent {
* @param {Object} form Form fields
* @param {Object} files array of file names and file content
* @param {Object} context the invocation context
* @param {Object} headers Request headers to set
* @return {Promise} A promise. fulfilled with {body, statusCode}, rejected with { statusCode, errorDescription, error, body }
*/
_request({ uri, method, data, auth, query, form, files, context, raw }) {
const req = this._buildRequest({ uri, method, data, auth, query, form, context, files });
_request({ uri, method, data, auth, query, form, files, context, raw, headers }) {
const req = this._buildRequest({ uri, method, data, auth, query, form, context, files, headers });

if (raw){
return req;
Expand Down Expand Up @@ -137,7 +140,7 @@ export default class Agent {
});
}

_buildRequest({ uri, method, data, auth, query, form, files, context, makerequest = request }) {
_buildRequest({ uri, method, data, auth, query, form, files, context, headers={}, makerequest = request }) {
const req = makerequest(method, uri);
if (this.prefix) {
req.use(this.prefix);
Expand All @@ -146,6 +149,11 @@ export default class Agent {
if (context) {
this._applyContext(req, context);
}
if (Object.keys(headers).length) {
for (const key of Object.keys(headers)) {
req.set(key, headers[key]);
}
}
if (query) {
req.query(query);
}
Expand Down
116 changes: 106 additions & 10 deletions src/Particle.js
Original file line number Diff line number Diff line change
Expand Up @@ -1500,6 +1500,102 @@ class Particle {
return this.get(`/v1/networks/${networkId}/devices`, auth, query, context);
}

/**
* Get product configuration
* @param {Object} options Options for this API call
* @param {String} options.product Team for this product ID or slug
* @param {String} options.auth Access Token
* @returns {Promise} A promise
*/
getProductConfiguration({ auth, product, context }){
return this.get(`/v1/products/${product}/config`, auth, undefined, context);
}

/**
* Get product configuration schema
* @param {Object} options Options for this API call
* @param {String} options.product Team for this product ID or slug
* @param {String} options.auth Access Token
* @returns {Promise} A promise
*/
getProductConfigurationSchema({ auth, product, context }){
return this.get(`/v1/products/${product}/config`, auth, undefined, context, {
'accept': 'application/schema+json'
});
}

/**
* Set product configuration
* @param {Object} options Options for this API call
* @param {String} options.product Team for this product ID or slug
* @param {String} options.auth Access Token
* @param {Object} opitons.config Product configuration to update
* @returns {Promise} A promise
*/
setProductConfiguration({ auth, product, context, config }){
return this.put(`/v1/products/${product}/config`, config, auth, context);
}

/**
* Set product configuration for a specific device within the product
* @param {Object} options Options for this API call
* @param {String} options.product Team for this product ID or slug
* @param {String} options.auth Access Token
* @param {Object} opitons.config Product configuration to update
* @param {String} options.deviceId Device ID to access
* @returns {Promise} A promise
*/
setProductDeviceConfiguration({ auth, product, deviceId, context, config }){
return this.put(`/v1/products/${product}/config/${deviceId}`, config, auth, context);
}

/**
* Query location for devices within a product
* @param {Object} options Options for this API call
* @param {String} options.product Team for this product ID or slug
* @param {String} options.auth Access Token
* @param {String} options.dateRange Start and end date in ISO8601 format, separated by comma, to query
* @param {String} options.rectBl Bottom left of the rectangular bounding box to query. Latitude and longitude separated by comma
* @param {String} options.rectTr Top right of the rectangular bounding box to query. Latitude and longitude separated by comma
* @param {String} options.deviceId Device ID prefix to include in the query
* @param {String} options.deviceName Device name prefix to include in the query
* @param {String} options.groups Array of group names to include in the query
* @param {String} options.page Page of results to display. Defaults to 1
* @param {String} options.perPage Number of results per page. Defaults to 20. Maximum of 100
* @returns {Promise} A promise
*/
getProductLocations({ auth, product, context, dateRange, rectBl, rectTr, deviceId, deviceName, groups, page, perPage }){
return this.get(`/v1/products/${product}/locations`, auth, {
date_range: dateRange,
rect_bl: rectBl,
rect_tr: rectTr,
device_id: deviceId,
device_name: deviceName,
groups,
page,
per_page: perPage
}, context);
}

/**
* Query location for one device within a product
* @param {Object} options Options for this API call
* @param {String} options.product Team for this product ID or slug
* @param {String} options.auth Access Token
* @param {String} options.dateRange Start and end date in ISO8601 format, separated by comma, to query
* @param {String} options.rectBl Bottom left of the rectangular bounding box to query. Latitude and longitude separated by comma
* @param {String} options.rectTr Top right of the rectangular bounding box to query. Latitude and longitude separated by comma
* @param {String} options.deviceId Device ID to query
* @returns {Promise} A promise
*/
getProductDeviceLocations({ auth, product, context, dateRange, rectBl, rectTr, deviceId }){
return this.get(`/v1/products/${product}/locations/${deviceId}`, auth, {
date_range: dateRange,
rect_bl: rectBl,
rect_tr: rectTr
}, context);
}

/**
* API URI to access a device
* @param {Object} options Options for this API call
Expand All @@ -1512,29 +1608,29 @@ class Particle {
return product ? `/v1/products/${product}/devices/${deviceId}` : `/v1/devices/${deviceId}`;
}

get(uri, auth, query, context){
get(uri, auth, query, context, headers){
context = this._buildContext(context);
return this.agent.get(uri, auth, query, context);
return this.agent.get(uri, auth, query, context, headers);
}

head(uri, auth, query, context){
head(uri, auth, query, context, headers){
context = this._buildContext(context);
return this.agent.head(uri, auth, query, context);
return this.agent.head(uri, auth, query, context, headers);
}

post(uri, data, auth, context){
post(uri, data, auth, context, headers){
context = this._buildContext(context);
return this.agent.post(uri, data, auth, context);
return this.agent.post(uri, data, auth, context, headers);
}

put(uri, data, auth, context){
put(uri, data, auth, context, headers){
context = this._buildContext(context);
return this.agent.put(uri, data, auth, context);
return this.agent.put(uri, data, auth, context, headers);
}

delete(uri, data, auth, context){
delete(uri, data, auth, context, headers){
context = this._buildContext(context);
return this.agent.delete(uri, data, auth, context);
return this.agent.delete(uri, data, auth, context, headers);
}

request(args){
Expand Down
26 changes: 20 additions & 6 deletions test/Agent.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('Agent', () => {
});

describe('resource operations', () => {
let context;
let context, headers;

beforeEach(() => {
context = { blah: {} };
Expand All @@ -38,39 +38,39 @@ describe('Agent', () => {
sut.request = sinon.stub();
sut.request.returns('123');
expect(sut.get('abcd', 'auth', 'query', context)).to.be.equal('123');
expect(sut.request).to.be.calledWith({ auth: 'auth', method: 'get', query: 'query', uri: 'abcd', context });
expect(sut.request).to.be.calledWith({ auth: 'auth', method: 'get', query: 'query', uri: 'abcd', context, headers });
});

it('can head a resource', () => {
const sut = new Agent();
sut.request = sinon.stub();
sut.request.returns('123');
expect(sut.head('abcd', 'auth', 'query', context)).to.be.equal('123');
expect(sut.request).to.be.calledWith({ auth: 'auth', method: 'head', uri: 'abcd', query: 'query', context });
expect(sut.request).to.be.calledWith({ auth: 'auth', method: 'head', uri: 'abcd', query: 'query', context, headers });
});

it('can post a resource', () => {
const sut = new Agent();
sut.request = sinon.stub();
sut.request.returns('123');
expect(sut.post('abcd', 'data', 'auth', context)).to.be.equal('123');
expect(sut.request).to.be.calledWith({ auth: 'auth', method: 'post', data: 'data', uri: 'abcd', context });
expect(sut.request).to.be.calledWith({ auth: 'auth', method: 'post', data: 'data', uri: 'abcd', context, headers });
});

it('can put a resource', () => {
const sut = new Agent();
sut.request = sinon.stub();
sut.request.returns('123');
expect(sut.put('abcd', 'data', 'auth', context)).to.be.equal('123');
expect(sut.request).to.be.calledWith({ auth: 'auth', method: 'put', data:'data', uri: 'abcd', context });
expect(sut.request).to.be.calledWith({ auth: 'auth', method: 'put', data:'data', uri: 'abcd', context, headers });
});

it('can delete a resource', () => {
const sut = new Agent();
sut.request = sinon.stub();
sut.request.returns('123');
expect(sut.delete('abcd', 'data', 'auth', context)).to.be.equal('123');
expect(sut.request).to.be.calledWith({ auth: 'auth', method: 'delete', data:'data', uri: 'abcd', context });
expect(sut.request).to.be.calledWith({ auth: 'auth', method: 'delete', data:'data', uri: 'abcd', context, headers });
});
});

Expand Down Expand Up @@ -252,6 +252,17 @@ describe('Agent', () => {
expect(extractFilename(req._formData, 'file2', 3)).to.eql('dir/file2path.cpp');
});

it('should set headers', () => {
const sut = new Agent();
const headers = {
'foo': 'bar',
'baz': 1
};
const req = sut._buildRequest({ uri: 'uri', method: 'get', headers });
expect(req.header.foo).to.eql(headers.foo);
expect(req.header.baz).to.eql(headers.baz);
});

if (!inBrowser()){
it('should handle Windows nested dirs', () => {
const sut = new Agent();
Expand Down Expand Up @@ -299,6 +310,7 @@ describe('Agent', () => {
expect(sut._request).calledOnce.calledWith({
uri: 'abc',
auth: undefined,
headers: {},
method: 'post',
data: '123',
query: 'all',
Expand All @@ -320,6 +332,7 @@ describe('Agent', () => {
uri: 'abc',
method:'post',
auth: undefined,
headers: {},
data: undefined,
files: undefined,
form: undefined,
Expand All @@ -345,6 +358,7 @@ describe('Agent', () => {
auth:'auth',
query: 'query',
form: 'form',
headers: undefined,
files: 'files',
context
};
Expand Down
20 changes: 10 additions & 10 deletions test/FakeAgent.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
export default class FakeAgent {
get(uri, auth, query = undefined, context) {
return this.request({ method: 'get', uri, auth, query, context });
get(uri, auth, query = undefined, context, headers) {
return this.request({ method: 'get', uri, auth, query, context, headers });
}

head(uri, auth, query, context) {
return this.request({ method: 'head', uri, auth, query, context });
head(uri, auth, query, context, headers) {
return this.request({ method: 'head', uri, auth, query, context, headers });
}

post(uri, data, auth, context) {
return this.request({ method: 'post', uri, data, auth, context });
post(uri, data, auth, context, headers) {
return this.request({ method: 'post', uri, data, auth, context, headers });
}

put(uri, data, auth, context) {
return this.request({ method: 'put', uri, data, auth, context });
put(uri, data, auth, context, headers) {
return this.request({ method: 'put', uri, data, auth, context, headers });
}

delete(uri, data, auth, context) {
return this.request({ method: 'delete', uri, data, auth, context });
delete(uri, data, auth, context, headers) {
return this.request({ method: 'delete', uri, data, auth, context, headers });
}

request(opts) {
Expand Down
Loading