UNPKG

cannery-adapter-rest

Version:
352 lines (294 loc) 12.6 kB
'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var ajax = require('then-request'); var debug = require('debug')('cannery-adapter-rest'); var adapterOptions = Symbol(); var endpointState = {}; var endpointResolver = {}; var storage = global.sessionStorage || {}; var RestAdapter = function () { function RestAdapter() { var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; var routes = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; _classCallCheck(this, RestAdapter); this.routes = routes; this[adapterOptions] = options; } _createClass(RestAdapter, [{ key: 'buildCacheKey', value: function buildCacheKey(url) { var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; var key = this.getUrl(url); if (options.qs) { key += '-' + JSON.stringify(options.qs); } if (options.headers) { key += '-' + JSON.stringify(options.headers); } return key; } }, { key: 'getRoutePath', value: function getRoutePath(model) { var routeArray = [model.constructor.name]; var child = model; while (child.getParent()) { routeArray.push(child.getParent().constructor.name); child = child.getParent(); } return routeArray.reverse().join('/'); } }, { key: 'parseOverrideRoute', value: function parseOverrideRoute(uri, model) { var parents = []; var child = model; while (child.getParent()) { parents.push(child.getParent().id); child = child.getParent(); } uri = uri.replace(/{id}/g, model.id); for (var i = 0; i < parents.length; i++) { uri = uri.replace('{parents[' + i + ']}', parents[i]); } return uri; } }, { key: 'getOverrideRoute', value: function getOverrideRoute(requestType, model) { var path = this.getRoutePath(model); debug('ROUTE', requestType, path); if (this.routes[path] && this.routes[path][requestType]) { return this.parseOverrideRoute(this.routes[path][requestType], model); } } }, { key: 'buildNestedUrl', value: function buildNestedUrl(url, child) { var parent = child.getParent(); url = child.getName() + '/' + child.id + '/' + url; if (parent) { return this.buildNestedUrl(url, parent); } else { return url; } } }, { key: 'create', value: function create(model, options) { var url = this.getCreateRoute(model); var requestOptions = this.createOptions(model, options); requestOptions.body = this.getBody(model); return ajax('POST', url, requestOptions).then(this.formatFetchResponse.bind(this)); } }, { key: 'createOptions', value: function createOptions(model, options) { options = options || {}; return Object.assign({}, { qs: options.qs, body: options.body, headers: Object.assign({}, this[adapterOptions].headers, options.headers) }); } }, { key: 'createOptionsWithEtags', value: function createOptionsWithEtags(model, options, cacheKey) { var requestOptions = this.createOptions(model, options); //requestOptions.headers['If-None-Match'] = storage[`cannery-e-${cacheKey}`]; return requestOptions; } }, { key: 'destroy', value: function destroy(model, options) { var url = this.getDestroyRoute(model); var requestOptions = this.createOptions(model, options); requestOptions.body = model.toJSON(); return ajax('DELETE', url, requestOptions).then(this.parseResponse.bind(this)); } }, { key: 'fetch', value: function fetch(model) { var _this = this; var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; var url = this.getFetchRoute(model); var cacheKey = this.buildCacheKey(url, options); var requestOptions = this.createOptionsWithEtags(model, options, cacheKey); if (endpointState[url] === 'fetching' || endpointState[url] === 'fetched') { return endpointResolver[url]; } endpointState[url] = 'fetching'; endpointResolver[url] = ajax('GET', url, requestOptions).then(function (response) { return _this.formatFetchResponse(response, cacheKey); }).then(function (response) { endpointState[url] = 'fetched'; return response; }); return endpointResolver[url]; } }, { key: 'fetchWithin', value: function fetchWithin(model, parent) { var _this2 = this; var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; var url = this.getFetchWithinRoute(model, parent); var cacheKey = this.buildCacheKey(url, options); var requestOptions = this.createOptionsWithEtags(model, options, cacheKey); if (endpointState[url] === 'fetching' || endpointState[url] === 'fetched') { return endpointResolver[url]; } endpointState[url] = 'fetching'; endpointResolver[url] = ajax('GET', this.getUrl(url), requestOptions).then(function (response) { return _this2.formatFetchResponse(response, cacheKey); }).then(function (response) { endpointState[url] = 'fetched'; return response; }); return endpointResolver[url]; } }, { key: 'findAll', value: function findAll(Model) { var _this3 = this; var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; var url = this.getFindAllRoute(Model); var cacheKey = this.buildCacheKey(url, options); var requestOptions = this.createOptionsWithEtags(null, options, cacheKey); return ajax('GET', url, requestOptions).then(function (response) { return _this3.formatFindAllResponse(response, cacheKey); }); } }, { key: 'findAllWithin', value: function findAllWithin(Model, parent) { var _this4 = this; var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; var url = this.getFindAllWithinRoute(Model, parent); var cacheKey = this.buildCacheKey(url, options); var requestOptions = this.createOptionsWithEtags(parent, options, cacheKey); return ajax('GET', this.getUrl(url), requestOptions).then(function (response) { return _this4.formatFindAllResponse(response, cacheKey); }); } }, { key: 'formatFetchResponse', value: function formatFetchResponse(response, cacheKey) { var body = this.parseResponse(response, cacheKey); var envelope = this.getOptions().envelope; return envelope ? body[envelope] : body; } }, { key: 'formatFindAllResponse', value: function formatFindAllResponse(response, cacheKey) { var body = this.parseResponse(response, cacheKey); var envelope = this.getOptions().arrayEnvelope; return envelope ? body[envelope] : body; } }, { key: 'getBody', value: function getBody(model) { return JSON.stringify(model.toJSON()); } }, { key: 'getCreateRoute', value: function getCreateRoute(model) { return this.getOverrideRoute('create', model) || this.getSingleFetchUrl(model); } }, { key: 'getDestroyRoute', value: function getDestroyRoute(model) { return this.getOverrideRoute('destroy', model) || this.getSingleFetchUrl(model); } }, { key: 'getFetchRoute', value: function getFetchRoute(model) { return this.getOverrideRoute('fetch', model) || this.getFetchUrl(model.getName(), model.id); } }, { key: 'getFetchWithinRoute', value: function getFetchWithinRoute(model, parent) { return this.getOverrideRoute('fetch', model) || this.buildNestedUrl(model.getName(), parent); } }, { key: 'getFindAllRoute', value: function getFindAllRoute(Model) { return this.getOverrideRoute('findAll', new Model()) || this.getUrl(new Model().getName()); } }, { key: 'getFindAllWithinRoute', value: function getFindAllWithinRoute(Model, parent) { var overrideModel = new Model(); overrideModel.getParent = function () { return parent; }; return this.getOverrideRoute('findAll', overrideModel) || this.buildNestedUrl(new Model().getName(), parent); } }, { key: 'getUpdateRoute', value: function getUpdateRoute(model) { return this.getOverrideRoute('update', model) || this.getSingleFetchUrl(model); } }, { key: 'getUrl', value: function getUrl(url) { var _getOptions = this.getOptions(); var urlRoot = _getOptions.urlRoot; return '' + (urlRoot || '') + url; } }, { key: 'getFetchUrl', value: function getFetchUrl(url, id) { if (id) { return this.getUrl(url) + '/' + id; } return this.getUrl(url); } }, { key: 'getSingleFetchUrl', value: function getSingleFetchUrl(model) { var parent = model.getParent(); var parentUrl = parent ? parent.getName() + '/' + parent.id + '/' : ''; return this.getFetchUrl(parentUrl + model.getName(), model.id); } }, { key: 'getOptions', value: function getOptions() { return this[adapterOptions]; } }, { key: 'getResponseBody', value: function getResponseBody(response, cacheKey) { var cachedData = storage['cannery-d-' + cacheKey]; if (response.statusCode === 304 && cachedData) { return cachedData; } if (response.headers.etag) { storage['cannery-e-' + cacheKey] = response.headers.etag; storage['cannery-d-' + cacheKey] = response.getBody(); } return response.getBody(); } }, { key: 'parseResponse', value: function parseResponse(response, cacheKey) { var body = this.getResponseBody(response, cacheKey); try { return JSON.parse(body); } catch (e) { return {}; } } }, { key: 'update', value: function update(model) { var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; var url = this.getUpdateRoute(model); var requestOptions = this.createOptions(model, options); requestOptions.body = this.getBody(model); return ajax('PUT', url, requestOptions).then(this.formatFetchResponse.bind(this)); } }]); return RestAdapter; }(); module.exports = RestAdapter;