chore: 🤖 change custom method requests to use POST on update

This commit is contained in:
Randall Morey committed 2020-08-07 16:29:56 -04:00
1 parent ee6999251d
commit 3b09ec80cd
4 files changed
+73

No files matched your search

+21
View File
@@ -1,4 +1,5 @@
import RESTAdapter from '@ember-data/adapter/rest';
import { serializeIntoHash } from '@ember-data/adapter/-private';
import AdapterBuildURLMixin from '../mixins/adapter-build-url';
import config from 'ember-get-config';
import { get, getWithDefault } from '@ember/object';
@@ -143,6 +144,26 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
return super.query(...arguments).then(prenormalizeArrayResponse);
}
/**
* Our API expects update calls with a custom method suffix
* (e.g. `:set-grants`) to be made with POST instead of PUT/PATCH.
* If this method is called with a custom method via `adapterOptions.method`,
* the API request will be made with POST. All other update requests are
* made as normal.
* @override
* @param {Store} store
* @param {Model} type
* @param {Snapshot} snapshot
* @return {Promise} promise
*/
updateRecord(store, type, snapshot) {
const method = get(snapshot, 'adapterOptions.method');
const data = serializeIntoHash(store, type, snapshot, {});
const id = snapshot.id;
const url = this.buildURL(type.modelName, id, snapshot, 'updateRecord');
return this.ajax(url, method ? 'POST' : 'PUT', { data });
}
/**
* Overrides default ajax method by rewritting PUT requests as PATCH.
* PATCH is the request method used by our API for updates.
+5
View File
@@ -20,6 +20,11 @@ export default class RoleSerializer extends ApplicationSerializer {
return serialized;
}
/**
* Returns a payload containing only the grants array.
* @param {Snapshot} snapshot
* @return {object}
*/
serializeWithGrants(snapshot) {
return {
grants: snapshot.attr('grants')
@@ -112,6 +112,23 @@ module('Unit | Adapter | application', function (hooks) {
adapter.ajax('/', 'PUT');
});
test('it rewrites PUT/PATCH to POST when `adapterOptions.method` is passed to `updateRecord`', function (assert) {
assert.expect(1);
const adapter = this.owner.lookup('adapter:application');
const store = this.owner.lookup('service:store');
const snapshot = store.createRecord('role', {})._createSnapshot();
snapshot.adapterOptions = {
method: 'custom-method'
}
// TODO this is icky, should be changed to a spy or stub
const originalAjax = RESTAdapter.prototype.ajax;
RESTAdapter.prototype.ajax = (url, type) => {
assert.equal(type, 'POST');
RESTAdapter.prototype.ajax = originalAjax;
};
adapter.updateRecord(store, {modelName: 'user'}, snapshot);
});
test('it prenormalizes "empty" responses into a form that the fetch-manager will not reject', async function (assert) {
assert.expect(1);
const adapter = this.owner.lookup('adapter:application');
+30
View File
@@ -1,12 +1,42 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
module('Unit | Model | role', function (hooks) {
setupTest(hooks);
setupMirage(hooks);
test('it exists', function(assert) {
let store = this.owner.lookup('service:store');
let model = store.createRecord('role', {});
assert.ok(model);
});
test('it has a `saveGrants` method that targets a specific POST API endpoint and serialization', async function (assert) {
assert.expect(1);
this.server.post('/v1/scopes/o_1/roles/123abc:set-grants', (schema, request) => {
const body = JSON.parse(request.requestBody);
assert.deepEqual(body, {
grants: ['grant1', 'grant2']
});
});
const store = this.owner.lookup('service:store');
store.push({
data: {
id: '123abc',
type: 'role',
attributes: {
name: 'Role',
description: 'Description',
grants: ['grant1', 'grant2'],
scope: {
scope_id: 'o_1',
type: 'scope'
}
}
}
});
const model = store.peekRecord('role', '123abc');
await model.saveGrants();
});
});