Introduce plugin.restApi(), deprecate other REST helper methods
Implement REST-related methods on Gerrit (get, post, etc).
REST-related methods on plugin now take plugin URL space into account,
to match GWT UI plugin JS API.
Example:
``` js
Gerrit.install(plugin => {
// deprecated:
plugin.get('/foo', json => {
// work work
});
Gerrit.post('/bar', {bar: 'space'}, json => {
// post succeeds
});
// recommended:
const pluginRestApi = plugin.restApi(plugin.url());
plugin.get('/foo').then(json => {
// work work
});
plugin.restApi().post('/bar', {bar: 'space'}).then(json => {
// post succeeds
});
});
```
Change-Id: I6f537507d76bddec1cac9159cebe1b720ab5caf8
This commit is contained in:
@@ -31,5 +31,6 @@ limitations under the License.
|
||||
<script src="gr-js-api-interface.js"></script>
|
||||
<script src="gr-plugin-endpoints.js"></script>
|
||||
<script src="gr-plugin-action-context.js"></script>
|
||||
<script src="gr-plugin-rest-api.js"></script>
|
||||
<script src="gr-public-js-api.js"></script>
|
||||
</dom-module>
|
||||
|
||||
@@ -96,7 +96,8 @@ limitations under the License.
|
||||
const response = {foo: 'foo'};
|
||||
getResponseObjectStub.returns(Promise.resolve(response));
|
||||
return plugin.get('/url', r => {
|
||||
assert.isTrue(sendStub.calledWith('GET', '/url'));
|
||||
assert.isTrue(sendStub.calledWith(
|
||||
'GET', 'http://test.com/plugins/testplugin/url'));
|
||||
assert.strictEqual(r, response);
|
||||
});
|
||||
});
|
||||
@@ -105,7 +106,8 @@ limitations under the License.
|
||||
const response = {foo: 'foo'};
|
||||
getResponseObjectStub.returns(Promise.resolve(response));
|
||||
return plugin.get('/url', r => 'rubbish').then(r => {
|
||||
assert.isTrue(sendStub.calledWith('GET', '/url'));
|
||||
assert.isTrue(sendStub.calledWith(
|
||||
'GET', 'http://test.com/plugins/testplugin/url'));
|
||||
assert.strictEqual(r, response);
|
||||
});
|
||||
});
|
||||
@@ -115,7 +117,8 @@ limitations under the License.
|
||||
const response = {bar: 'bar'};
|
||||
getResponseObjectStub.returns(Promise.resolve(response));
|
||||
return plugin.post('/url', payload, r => {
|
||||
assert.isTrue(sendStub.calledWith('POST', '/url', payload));
|
||||
assert.isTrue(sendStub.calledWith(
|
||||
'POST', 'http://test.com/plugins/testplugin/url', payload));
|
||||
assert.strictEqual(r, response);
|
||||
});
|
||||
});
|
||||
@@ -125,7 +128,8 @@ limitations under the License.
|
||||
const response = {bar: 'bar'};
|
||||
getResponseObjectStub.returns(Promise.resolve(response));
|
||||
return plugin.put('/url', payload, r => {
|
||||
assert.isTrue(sendStub.calledWith('PUT', '/url', payload));
|
||||
assert.isTrue(sendStub.calledWith(
|
||||
'PUT', 'http://test.com/plugins/testplugin/url', payload));
|
||||
assert.strictEqual(r, response);
|
||||
});
|
||||
});
|
||||
@@ -134,7 +138,8 @@ limitations under the License.
|
||||
const response = {status: 204};
|
||||
sendStub.returns(Promise.resolve(response));
|
||||
return plugin.delete('/url', r => {
|
||||
assert.isTrue(sendStub.calledWithExactly('DELETE', '/url'));
|
||||
assert.isTrue(sendStub.calledWithExactly(
|
||||
'DELETE', 'http://test.com/plugins/testplugin/url'));
|
||||
assert.strictEqual(r, response);
|
||||
});
|
||||
});
|
||||
@@ -145,7 +150,8 @@ limitations under the License.
|
||||
return plugin.delete('/url', r => {
|
||||
throw new Error('Should not resolve');
|
||||
}).catch(err => {
|
||||
assert.isTrue(sendStub.calledWith('DELETE', '/url'));
|
||||
assert.isTrue(sendStub.calledWith(
|
||||
'DELETE', 'http://test.com/plugins/testplugin/url'));
|
||||
assert.equal('text', err);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright (C) 2017 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
(function(window) {
|
||||
'use strict';
|
||||
|
||||
function GrPluginRestApi(opt_prefix) {
|
||||
this.opt_prefix = opt_prefix || '';
|
||||
this._restApi = document.createElement('gr-rest-api-interface');
|
||||
}
|
||||
|
||||
GrPluginRestApi.prototype.getLoggedIn = function() {
|
||||
return this._restApi.getLoggedIn();
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch and return native browser REST API Response.
|
||||
* @param {string} method HTTP Method (GET, POST, etc)
|
||||
* @param {string} url URL without base path or plugin prefix
|
||||
* @param {Object=} payload Respected for POST and PUT only.
|
||||
* @return {!Promise}
|
||||
*/
|
||||
GrPluginRestApi.prototype.fetch = function(method, url, opt_payload) {
|
||||
return this._restApi.send(method, this.opt_prefix + url, opt_payload);
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch and parse REST API response, if request succeeds.
|
||||
* @param {string} method HTTP Method (GET, POST, etc)
|
||||
* @param {string} url URL without base path or plugin prefix
|
||||
* @param {Object=} payload Respected for POST and PUT only.
|
||||
* @return {!Promise} resolves on success, rejects on error.
|
||||
*/
|
||||
GrPluginRestApi.prototype.send = function(method, url, opt_payload) {
|
||||
return this.fetch(method, url, opt_payload).then(response => {
|
||||
if (response.status < 200 || response.status >= 300) {
|
||||
return response.text().then(text => {
|
||||
if (text) {
|
||||
return Promise.reject(text);
|
||||
} else {
|
||||
return Promise.reject(response.status);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return this._restApi.getResponseObject(response);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} url URL without base path or plugin prefix
|
||||
* @return {!Promise} resolves on success, rejects on error.
|
||||
*/
|
||||
GrPluginRestApi.prototype.get = function(url) {
|
||||
return this.send('GET', url);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} url URL without base path or plugin prefix
|
||||
* @return {!Promise} resolves on success, rejects on error.
|
||||
*/
|
||||
GrPluginRestApi.prototype.post = function(url, opt_payload) {
|
||||
return this.send('POST', url, opt_payload);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} url URL without base path or plugin prefix
|
||||
* @return {!Promise} resolves on success, rejects on error.
|
||||
*/
|
||||
GrPluginRestApi.prototype.put = function(url, opt_payload) {
|
||||
return this.send('PUT', url, opt_payload);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} url URL without base path or plugin prefix
|
||||
* @return {!Promise} resolves on 204, rejects on error.
|
||||
*/
|
||||
GrPluginRestApi.prototype.delete = function(url) {
|
||||
return this.fetch('DELETE', url).then(response => {
|
||||
if (response.status !== 204) {
|
||||
return response.text().then(text => {
|
||||
if (text) {
|
||||
return Promise.reject(text);
|
||||
} else {
|
||||
return Promise.reject(response.status);
|
||||
}
|
||||
});
|
||||
}
|
||||
return response;
|
||||
});
|
||||
};
|
||||
|
||||
window.GrPluginRestApi = GrPluginRestApi;
|
||||
})(window);
|
||||
@@ -0,0 +1,124 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
|
||||
<title>gr-plugin-rest-api</title>
|
||||
|
||||
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
|
||||
<script src="../../../bower_components/web-component-tester/browser.js"></script>
|
||||
<link rel="import" href="../../../test/common-test-setup.html"/>
|
||||
<link rel="import" href="gr-js-api-interface.html"/>
|
||||
|
||||
<script>
|
||||
suite('gr-plugin-rest-api tests', () => {
|
||||
let instance;
|
||||
let sandbox;
|
||||
let getResponseObjectStub;
|
||||
let sendStub;
|
||||
|
||||
setup(() => {
|
||||
sandbox = sinon.sandbox.create();
|
||||
getResponseObjectStub = sandbox.stub().returns(Promise.resolve());
|
||||
sendStub = sandbox.stub().returns(Promise.resolve({status: 200}));
|
||||
stub('gr-rest-api-interface', {
|
||||
getAccount() {
|
||||
return Promise.resolve({name: 'Judy Hopps'});
|
||||
},
|
||||
getResponseObject: getResponseObjectStub,
|
||||
send(...args) {
|
||||
return sendStub(...args);
|
||||
},
|
||||
});
|
||||
Gerrit._setPluginsCount(1);
|
||||
Gerrit.install(p => { plugin = p; }, '0.1',
|
||||
'http://test.com/plugins/testplugin/static/test.js');
|
||||
instance = new GrPluginRestApi();
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
test('fetch', () => {
|
||||
const payload = {foo: 'foo'};
|
||||
return instance.fetch('HTTP_METHOD', '/url', payload).then(r => {
|
||||
assert.isTrue(sendStub.calledWith('HTTP_METHOD', '/url', payload));
|
||||
assert.equal(r.status, 200);
|
||||
assert.isFalse(getResponseObjectStub.called);
|
||||
});
|
||||
});
|
||||
|
||||
test('send', () => {
|
||||
const payload = {foo: 'foo'};
|
||||
const response = {bar: 'bar'};
|
||||
getResponseObjectStub.returns(Promise.resolve(response));
|
||||
return instance.send('HTTP_METHOD', '/url', payload).then(r => {
|
||||
assert.isTrue(sendStub.calledWith('HTTP_METHOD', '/url', payload));
|
||||
assert.strictEqual(r, response);
|
||||
});
|
||||
});
|
||||
|
||||
test('get', () => {
|
||||
const response = {foo: 'foo'};
|
||||
getResponseObjectStub.returns(Promise.resolve(response));
|
||||
return instance.get('/url').then(r => {
|
||||
assert.isTrue(sendStub.calledWith('GET', '/url'));
|
||||
assert.strictEqual(r, response);
|
||||
});
|
||||
});
|
||||
|
||||
test('post', () => {
|
||||
const payload = {foo: 'foo'};
|
||||
const response = {bar: 'bar'};
|
||||
getResponseObjectStub.returns(Promise.resolve(response));
|
||||
return instance.post('/url', payload).then(r => {
|
||||
assert.isTrue(sendStub.calledWith('POST', '/url', payload));
|
||||
assert.strictEqual(r, response);
|
||||
});
|
||||
});
|
||||
|
||||
test('put', () => {
|
||||
const payload = {foo: 'foo'};
|
||||
const response = {bar: 'bar'};
|
||||
getResponseObjectStub.returns(Promise.resolve(response));
|
||||
return instance.put('/url', payload).then(r => {
|
||||
assert.isTrue(sendStub.calledWith('PUT', '/url', payload));
|
||||
assert.strictEqual(r, response);
|
||||
});
|
||||
});
|
||||
|
||||
test('delete works', () => {
|
||||
const response = {status: 204};
|
||||
sendStub.returns(Promise.resolve(response));
|
||||
return instance.delete('/url').then(r => {
|
||||
assert.isTrue(sendStub.calledWith('DELETE', '/url'));
|
||||
assert.strictEqual(r, response);
|
||||
});
|
||||
});
|
||||
|
||||
test('delete fails', () => {
|
||||
sendStub.returns(Promise.resolve(
|
||||
{status: 400, text() { return Promise.resolve('text'); }}));
|
||||
return instance.delete('/url').then(r => {
|
||||
throw new Error('Should not resolve');
|
||||
}).catch(err => {
|
||||
assert.isTrue(sendStub.calledWith('DELETE', '/url'));
|
||||
assert.equal('text', err);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -32,6 +32,28 @@
|
||||
return _restAPI;
|
||||
};
|
||||
|
||||
// TODO (viktard): deprecate in favor of GrPluginRestApi.
|
||||
function send(method, url, opt_callback, opt_payload) {
|
||||
return getRestAPI().send(method, url, opt_payload).then(response => {
|
||||
if (response.status < 200 || response.status >= 300) {
|
||||
return response.text().then(text => {
|
||||
if (text) {
|
||||
return Promise.reject(text);
|
||||
} else {
|
||||
return Promise.reject(response.status);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return getRestAPI().getResponseObject(response);
|
||||
}
|
||||
}).then(response => {
|
||||
if (opt_callback) {
|
||||
opt_callback(response);
|
||||
}
|
||||
return response;
|
||||
});
|
||||
}
|
||||
|
||||
const API_VERSION = '0.1';
|
||||
|
||||
/**
|
||||
@@ -131,55 +153,27 @@
|
||||
};
|
||||
|
||||
Plugin.prototype._send = function(method, url, opt_callback, opt_payload) {
|
||||
return getRestAPI().send(method, url, opt_payload).then(response => {
|
||||
if (response.status < 200 || response.status >= 300) {
|
||||
return response.text().then(text => {
|
||||
if (text) {
|
||||
return Promise.reject(text);
|
||||
} else {
|
||||
return Promise.reject(response.status);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return getRestAPI().getResponseObject(response);
|
||||
}
|
||||
}).then(response => {
|
||||
if (opt_callback) {
|
||||
opt_callback(response);
|
||||
}
|
||||
return response;
|
||||
});
|
||||
return send(method, this.url(url), opt_callback, opt_payload);
|
||||
};
|
||||
|
||||
Plugin.prototype.get = function(url, opt_callback) {
|
||||
console.warn('.get() is deprecated! Use .restApi().get()');
|
||||
return this._send('GET', url, opt_callback);
|
||||
},
|
||||
};
|
||||
|
||||
Plugin.prototype.post = function(url, payload, opt_callback) {
|
||||
console.warn('.post() is deprecated! Use .restApi().post()');
|
||||
return this._send('POST', url, opt_callback, payload);
|
||||
},
|
||||
};
|
||||
|
||||
Plugin.prototype.put = function(url, payload, opt_callback) {
|
||||
console.warn('.put() is deprecated! Use .restApi().put()');
|
||||
return this._send('PUT', url, opt_callback, payload);
|
||||
},
|
||||
};
|
||||
|
||||
Plugin.prototype.delete = function(url, opt_callback) {
|
||||
return getRestAPI().send('DELETE', url).then(response => {
|
||||
if (response.status !== 204) {
|
||||
return response.text().then(text => {
|
||||
if (text) {
|
||||
return Promise.reject(text);
|
||||
} else {
|
||||
return Promise.reject(response.status);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (opt_callback) {
|
||||
opt_callback(response);
|
||||
}
|
||||
return response;
|
||||
});
|
||||
},
|
||||
return Gerrit.delete(this.url(url), opt_callback);
|
||||
};
|
||||
|
||||
Plugin.prototype.changeActions = function() {
|
||||
return new GrChangeActionsInterface(this,
|
||||
@@ -205,6 +199,17 @@
|
||||
return new GrProjectApi(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* To make REST requests for plugin-provided endpoints, use
|
||||
* @example
|
||||
* const pluginRestApi = plugin.restApi(plugin.url());
|
||||
*
|
||||
* @param {string} Base url for subsequent .get(), .post() etc requests.
|
||||
*/
|
||||
Plugin.prototype.restApi = function(opt_prefix) {
|
||||
return new GrPluginRestApi(opt_prefix);
|
||||
};
|
||||
|
||||
Plugin.prototype.attributeHelper = function(element) {
|
||||
return new GrAttributeHelper(element);
|
||||
};
|
||||
@@ -272,7 +277,7 @@
|
||||
|
||||
Gerrit.getPluginName = function() {
|
||||
console.warn('Gerrit.getPluginName is not supported in PolyGerrit.',
|
||||
'Please use self.getPluginName() instead.');
|
||||
'Please use plugin.getPluginName() instead.');
|
||||
};
|
||||
|
||||
Gerrit.css = function(rulesStr) {
|
||||
@@ -310,9 +315,45 @@
|
||||
};
|
||||
|
||||
Gerrit.getLoggedIn = function() {
|
||||
console.warn('Gerrit.getLoggedIn() is deprecated! ' +
|
||||
'Use plugin.restApi().getLoggedIn()');
|
||||
return document.createElement('gr-rest-api-interface').getLoggedIn();
|
||||
};
|
||||
|
||||
Gerrit.get = function(url, callback) {
|
||||
console.warn('.get() is deprecated! Use plugin.restApi().get()');
|
||||
send('GET', url, callback);
|
||||
};
|
||||
|
||||
Gerrit.post = function(url, payload, callback) {
|
||||
console.warn('.post() is deprecated! Use plugin.restApi().post()');
|
||||
send('POST', url, callback, payload);
|
||||
};
|
||||
|
||||
Gerrit.put = function(url, payload, callback) {
|
||||
console.warn('.put() is deprecated! Use plugin.restApi().put()');
|
||||
send('PUT', url, callback, payload);
|
||||
};
|
||||
|
||||
Gerrit.delete = function(url, opt_callback) {
|
||||
console.warn('.delete() is deprecated! Use plugin.restApi().delete()');
|
||||
return getRestAPI().send('DELETE', url).then(response => {
|
||||
if (response.status !== 204) {
|
||||
return response.text().then(text => {
|
||||
if (text) {
|
||||
return Promise.reject(text);
|
||||
} else {
|
||||
return Promise.reject(response.status);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (opt_callback) {
|
||||
opt_callback(response);
|
||||
}
|
||||
return response;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Polyfill GWT API dependencies to avoid runtime exceptions when loading
|
||||
* GWT-compiled plugins.
|
||||
|
||||
@@ -1372,23 +1372,25 @@
|
||||
options.headers.set(header, opt_headers[header]);
|
||||
}
|
||||
}
|
||||
return this._auth.fetch(this.getBaseUrl() + url, options)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
if (opt_errFn) {
|
||||
return opt_errFn.call(opt_ctx || null, response);
|
||||
}
|
||||
this.fire('server-error', {response});
|
||||
}
|
||||
return response;
|
||||
}).catch(err => {
|
||||
this.fire('network-error', {error: err});
|
||||
if (opt_errFn) {
|
||||
return opt_errFn.call(opt_ctx, null, err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
if (!url.startsWith('http')) {
|
||||
url = this.getBaseUrl() + url;
|
||||
}
|
||||
return this._auth.fetch(url, options).then(response => {
|
||||
if (!response.ok) {
|
||||
if (opt_errFn) {
|
||||
return opt_errFn.call(opt_ctx || null, response);
|
||||
}
|
||||
this.fire('server-error', {response});
|
||||
}
|
||||
return response;
|
||||
}).catch(err => {
|
||||
this.fire('network-error', {error: err});
|
||||
if (opt_errFn) {
|
||||
return opt_errFn.call(opt_ctx, null, err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,6 +147,7 @@ limitations under the License.
|
||||
'shared/gr-js-api-interface/gr-change-actions-js-api_test.html',
|
||||
'shared/gr-js-api-interface/gr-change-reply-js-api_test.html',
|
||||
'shared/gr-js-api-interface/gr-js-api-interface_test.html',
|
||||
'shared/gr-js-api-interface/gr-plugin-rest-api_test.html',
|
||||
'shared/gr-limited-text/gr-limited-text_test.html',
|
||||
'shared/gr-linked-chip/gr-linked-chip_test.html',
|
||||
'shared/gr-linked-text/gr-linked-text_test.html',
|
||||
|
||||
Reference in New Issue
Block a user