diff --git a/ui-v2/app/adapters/application.js b/ui-v2/app/adapters/application.js index b28ed0a86..07532cc0e 100644 --- a/ui-v2/app/adapters/application.js +++ b/ui-v2/app/adapters/application.js @@ -13,6 +13,7 @@ export const REQUEST_DELETE = 'deleteRecord'; export const DATACENTER_QUERY_PARAM = 'dc'; +import { HEADERS_SYMBOL as HTTP_HEADERS_SYMBOL } from 'consul-ui/utils/http/consul'; export default Adapter.extend({ namespace: 'v1', repo: service('settings'), @@ -22,6 +23,24 @@ export default Adapter.extend({ ...this._super(...arguments), }; }, + handleResponse: function(status, headers, response, requestData) { + // The ember-data RESTAdapter drops the headers after this call, + // and there is no where else to get to these + // save them to response[HTTP_HEADERS_SYMBOL] for the moment + // so we can save them as meta in the serializer... + if ( + (typeof response == 'object' && response.constructor == Object) || + Array.isArray(response) + ) { + // lowercase everything incase we get browser inconsistencies + const lower = {}; + Object.keys(headers).forEach(function(key) { + lower[key.toLowerCase()] = headers[key]; + }); + response[HTTP_HEADERS_SYMBOL] = lower; + } + return this._super(status, headers, response, requestData); + }, handleBooleanResponse: function(url, response, primary, slug) { return { // consider a check for a boolean, also for future me, diff --git a/ui-v2/app/serializers/application.js b/ui-v2/app/serializers/application.js index d7468ee8f..e75c96559 100644 --- a/ui-v2/app/serializers/application.js +++ b/ui-v2/app/serializers/application.js @@ -1,19 +1,59 @@ import Serializer from 'ember-data/serializers/rest'; +import { get } from '@ember/object'; +import { + HEADERS_SYMBOL as HTTP_HEADERS_SYMBOL, + HEADERS_INDEX as HTTP_HEADERS_INDEX, + HEADERS_DIGEST as HTTP_HEADERS_DIGEST, +} from 'consul-ui/utils/http/consul'; export default Serializer.extend({ // this could get confusing if you tried to override // say `normalizeQueryResponse` // TODO: consider creating a method for each one of the `normalize...Response` family normalizeResponse: function(store, primaryModelClass, payload, id, requestType) { - return this._super( + // Pick the meta/headers back off the payload and cleanup + // before we go through serializing + const headers = payload[HTTP_HEADERS_SYMBOL] || {}; + delete payload[HTTP_HEADERS_SYMBOL]; + const normalizedPayload = this.normalizePayload(payload, id, requestType); + const response = this._super( store, primaryModelClass, { - [primaryModelClass.modelName]: this.normalizePayload(payload, id, requestType), + [primaryModelClass.modelName]: normalizedPayload, }, id, requestType ); + // put the meta onto the response, here this is ok + // as JSON-API allows this and our specific data is now in + // response[primaryModelClass.modelName] + // so we aren't in danger of overwriting anything + // (which was the reason for the Symbol-like property earlier) + // use a method modelled on ember-data methods so we have the opportunity to + // do this on a per-model level + response.meta = this.normalizeMeta( + store, + primaryModelClass, + headers, + normalizedPayload, + id, + requestType + ); + return response; + }, + normalizeMeta: function(store, primaryModelClass, headers, payload, id, requestType) { + const meta = { + index: headers[HTTP_HEADERS_INDEX], + digest: headers[HTTP_HEADERS_DIGEST], + date: headers['date'], + }; + if (requestType === 'query') { + meta.ids = payload.map(item => { + return get(item, this.primaryKey); + }); + } + return meta; }, normalizePayload: function(payload, id, requestType) { return payload; diff --git a/ui-v2/app/utils/http/consul.js b/ui-v2/app/utils/http/consul.js new file mode 100644 index 000000000..f81e47d36 --- /dev/null +++ b/ui-v2/app/utils/http/consul.js @@ -0,0 +1,3 @@ +export const HEADERS_SYMBOL = '__consul_ui_http_headers__'; +export const HEADERS_INDEX = 'x-consul-index'; +export const HEADERS_DIGEST = 'x-consul-contenthash';