Implement defaultData on silverstripe-backend

This commit is contained in:
Ingo Schommer 2016-04-18 08:25:53 +12:00 committed by Damian Mooyman
parent ef6a1f33ee
commit 572d8427e0
4 changed files with 49 additions and 10 deletions

View File

@ -1,6 +1,7 @@
import fetch from 'isomorphic-fetch'; import fetch from 'isomorphic-fetch';
import es6promise from 'es6-promise'; import es6promise from 'es6-promise';
import qs from 'qs'; import qs from 'qs';
import merge from 'merge';
es6promise.polyfill(); es6promise.polyfill();
@ -50,6 +51,8 @@ class SilverStripeBackend {
* - responseFormat: the content-type of the response data. Decoding will be handled for you. * - responseFormat: the content-type of the response data. Decoding will be handled for you.
* - payloadSchema: Definition for how the payload data passed into the created method * - payloadSchema: Definition for how the payload data passed into the created method
* will be processed. See "Payload Schema" * will be processed. See "Payload Schema"
* - defaultData: Data to merge into the payload
* (which is passed into the returned method when invoked)
* *
* # Payload Formats * # Payload Formats
* *
@ -257,6 +260,7 @@ class SilverStripeBackend {
payloadFormat: 'application/x-www-form-url-encoded', payloadFormat: 'application/x-www-form-url-encoded',
responseFormat: 'application/json', responseFormat: 'application/json',
payloadSchema: {}, payloadSchema: {},
defaultData: {},
}, endpointSpec); }, endpointSpec);
// Substitute shorcut format values with their full mime types // Substitute shorcut format values with their full mime types
@ -270,18 +274,20 @@ class SilverStripeBackend {
} }
); );
return (data) => { return (data = {}) => {
const headers = { const headers = {
Accept: refinedSpec.responseFormat, Accept: refinedSpec.responseFormat,
'Content-Type': refinedSpec.payloadFormat, 'Content-Type': refinedSpec.payloadFormat,
}; };
const mergedData = merge.recursive({}, refinedSpec.defaultData, data);
// Replace url placeholders, and add query parameters // Replace url placeholders, and add query parameters
// from the payload based on the schema spec. // from the payload based on the schema spec.
const url = applySchemaToUrl( const url = applySchemaToUrl(
refinedSpec.payloadSchema, refinedSpec.payloadSchema,
refinedSpec.url, refinedSpec.url,
data, mergedData,
// Always add full payload data to GET requests. // Always add full payload data to GET requests.
// GET requests with a HTTP body are technically legal, // GET requests with a HTTP body are technically legal,
// but throw an error in the WHATWG fetch() implementation. // but throw an error in the WHATWG fetch() implementation.
@ -292,7 +298,7 @@ class SilverStripeBackend {
refinedSpec.payloadFormat, refinedSpec.payloadFormat,
// Filter raw data through the defined schema, // Filter raw data through the defined schema,
// potentially removing keys because they're // potentially removing keys because they're
applySchemaToData(refinedSpec.payloadSchema, data) applySchemaToData(refinedSpec.payloadSchema, mergedData)
); );
const args = refinedSpec.method.toLowerCase() === 'get' const args = refinedSpec.method.toLowerCase() === 'get'

View File

@ -4,6 +4,7 @@
jest.unmock('isomorphic-fetch'); jest.unmock('isomorphic-fetch');
jest.unmock('../silverstripe-backend'); jest.unmock('../silverstripe-backend');
jest.unmock('qs'); jest.unmock('qs');
jest.unmock('merge');
import backend from '../silverstripe-backend'; import backend from '../silverstripe-backend';
@ -191,10 +192,10 @@ describe('SilverStripeBackend', () => {
two: { urlReplacement: ':two' }, two: { urlReplacement: ':two' },
}, },
}); });
const promise = endpoint({ endpoint({
one: 1, one: 1,
two: 2, two: 2,
three: 3 three: 3,
}); });
expect(mock.post.mock.calls[0][0]).toEqual('http://example.com/1/2/?foo=bar'); expect(mock.post.mock.calls[0][0]).toEqual('http://example.com/1/2/?foo=bar');
expect(mock.post.mock.calls[0][1]).toEqual('two=2&three=3'); expect(mock.post.mock.calls[0][1]).toEqual('two=2&three=3');
@ -217,10 +218,10 @@ describe('SilverStripeBackend', () => {
three: { querystring: true }, three: { querystring: true },
}, },
}); });
const promise = endpoint({ endpoint({
one: 1, one: 1,
two: 2, two: 2,
three: 3 three: 3,
}); });
expect(mock.post.mock.calls[0][0]).toEqual('http://example.com/1/2/?foo=bar&three=3'); expect(mock.post.mock.calls[0][0]).toEqual('http://example.com/1/2/?foo=bar&three=3');
expect(mock.post.mock.calls[0][1]).toEqual('{"two":2}'); expect(mock.post.mock.calls[0][1]).toEqual('{"two":2}');
@ -242,16 +243,43 @@ describe('SilverStripeBackend', () => {
three: { querystring: true }, three: { querystring: true },
}, },
}); });
const promise = endpoint({ endpoint({
one: 1, one: 1,
two: 2, two: 2,
three: 3 three: 3,
}); });
expect(mock.get.mock.calls[0][0]).toEqual('http://example.com/1/2/?foo=bar&two=2&three=3'); expect(mock.get.mock.calls[0][0]).toEqual('http://example.com/1/2/?foo=bar&two=2&three=3');
expect(mock.get.mock.calls[0][1]).toEqual({ expect(mock.get.mock.calls[0][1]).toEqual({
Accept: 'application/json', Accept: 'application/json',
'Content-Type': 'application/x-www-form-url-encoded' 'Content-Type': 'application/x-www-form-url-encoded',
}); });
}); });
it('should merge defaultData into data argument', () => {
const mock = getBackendMock({
text: () => Promise.resolve('{"status":"ok"}'),
headers: new Headers({
'Content-Type': 'application/json',
}),
});
const endpoint = mock.createEndpointFetcher({
url: 'http://example.com/',
method: 'post',
payloadFormat: 'json',
defaultData: { one: 1, two: 2, four: { fourOne: true } },
});
endpoint({
two: 'updated',
three: 3,
four: { fourTwo: true },
});
expect(mock.post.mock.calls[0][0]).toEqual('http://example.com/');
expect(mock.post.mock.calls[0][1]).toEqual(JSON.stringify({
one: 1,
two: 'updated',
four: { fourOne: true, fourTwo: true },
three: 3,
}));
});
}); });
}); });

4
npm-shrinkwrap.json generated
View File

@ -12759,6 +12759,10 @@
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/json-js/-/json-js-1.1.2.tgz" "resolved": "https://registry.npmjs.org/json-js/-/json-js-1.1.2.tgz"
}, },
"merge": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz"
},
"merge-stream": { "merge-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.0.tgz",

View File

@ -46,6 +46,7 @@
"isomorphic-fetch": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", "isomorphic-fetch": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
"jquery-sizes": "^0.33.0", "jquery-sizes": "^0.33.0",
"json-js": "^1.1.2", "json-js": "^1.1.2",
"merge": "^1.2.0",
"page.js": "^4.13.3", "page.js": "^4.13.3",
"qs": "^6.1.0", "qs": "^6.1.0",
"react": "^0.14.8", "react": "^0.14.8",