216 lines
6.1 KiB
JavaScript
Raw Normal View History

2016-01-22 15:40:43 +01:00
'use strict';
/**
* Module dependencies
*/
// Public node modules.
const _ = require('lodash');
const JSONAPISerializer = require('jsonapi-serializer');
2016-01-28 16:21:25 +01:00
const utils = require('../utils/utils');
2016-01-22 15:40:43 +01:00
/**
* JSON API helper
*/
module.exports = {
default: {},
/**
* Set response
*/
set: function (ctx, matchedRoute, actionRoute) {
2016-01-28 16:21:25 +01:00
const object = utils.getObject(matchedRoute);
const type = utils.getType(ctx, actionRoute.controller);
// Fetch a relationship that does not exist
// Reject related request with `include` parameter
if (_.isUndefined(type) || (type === 'related' && ctx.params.hasOwnProperty('include'))) {
ctx.response.status = 404;
ctx.response.body = '';
return false;
}
// Fetch and format value
const value = this.fetchValue(ctx, object);
2016-01-26 15:35:25 +01:00
ctx.response.body = this.serialize(ctx, type, object, value);
},
/**
* Serialize response with JSON API specification
*/
2016-01-26 15:35:25 +01:00
serialize: function (ctx, type, object, value) {
// TODO:
// - Handle configuration with a file to improve flexibility of JSON API support
const toSerialize = {
topLevelLinks: {self: ctx.request.origin + ctx.request.url},
keyForAttribute: 'camelCase',
pluralizeType: false,
typeForAttribute: function (currentType) {
if (strapi.models.hasOwnProperty(type)) {
2016-01-26 15:35:25 +01:00
return _.first(_.reject(_.map(strapi.models[type].associations, function (relation) {
return (relation.alias === currentType) ? relation.model || relation.collection : undefined;
2016-01-26 15:35:25 +01:00
}), _.isUndefined)) || currentType;
}
}
};
2016-01-28 16:21:25 +01:00
const PK = utils.getPK(type);
if (_.isArray(value) && !_.isEmpty(value)) {
// Array
if (!_.isNull(PK)) {
_.forEach(value, function (record) {
record[PK] = record[PK].toString();
});
}
toSerialize.dataLinks = {
self: function (record) {
return ctx.request.origin + ctx.request.url + '/' + record.id;
}
};
toSerialize.attributes = _.keys(value[0]);
} else if (_.isObject(value) && !_.isEmpty(value)) {
// Object
if (!_.isNull(PK)) {
value[PK] = value[PK].toString();
}
toSerialize.attributes = _.keys(value);
}
2016-01-26 15:35:25 +01:00
switch (object) {
case 'collection':
this.includedRelationShips(ctx, toSerialize, type);
break;
case 'ressource':
this.includedRelationShips(ctx, toSerialize, type);
break;
case 'relationships':
// Remove data key
delete toSerialize.dataLinks;
delete toSerialize.attributes;
// Dirty way to set related URL
toSerialize.topLevelLinks.related = toSerialize.topLevelLinks.self.replace('relationships/', '');
break;
case 'related':
this.includedRelationShips(ctx, toSerialize, type);
2016-01-26 15:35:25 +01:00
break;
default:
break;
}
return new JSONAPISerializer(type, value, toSerialize);
},
/**
* Include relationships values to the object
*/
includedRelationShips: function (ctx, toSerialize, type) {
const self = this;
if (strapi.models.hasOwnProperty(type)) {
_.forEach(strapi.models[type].associations, function (relation) {
switch (relation.nature) {
case 'oneToOne':
case 'manyToOne':
// Object
toSerialize[relation.alias] = {
2016-01-28 16:21:25 +01:00
ref: utils.getPK(relation.model),
attributes: _.keys(strapi.models[type].attributes),
relationshipLinks: {
2016-01-26 15:35:25 +01:00
self: function (record) {
return ctx.request.origin + '/' + type + '/' + record.id + '/relationships/' + relation.alias;
},
related: function (record) {
return ctx.request.origin + '/' + type + '/' + record.id;
}
},
includedLinks: {
self: function (data, record) {
return ctx.request.origin + '/' + relation.model + '/' + record.id;
}
}
};
break;
case 'oneToMany':
case 'manyToMany':
// Array
toSerialize[relation.alias] = {
2016-01-28 16:21:25 +01:00
ref: utils.getPK(relation.collection),
typeForAttribute: relation.collection,
attributes: _.keys(strapi.models[type].attributes),
relationshipLinks: {
2016-01-26 15:35:25 +01:00
self: function (record) {
return ctx.request.origin + '/' + type + '/' + record.id + '/relationships/' + relation.alias;
},
related: function (record) {
return ctx.request.origin + '/' + type + '/' + record.id;
}
},
includedLinks: {
self: function (data, record) {
return ctx.request.origin + '/' + relation.collection + '/' + record.id;
}
}
};
break;
default:
}
});
}
},
/**
* Fetch and format value
*/
fetchValue: function (ctx, object) {
const data = ctx.body;
switch (object) {
case 'collection':
if ((_.isArray(data) && _.size(data) > 1) || _.isObject(data)) {
return data;
} else if (_.isArray(data) && (_.size(data) === 1 || _.size(data) === 0)) {
return _.isObject(_.first(data)) ? _.first(data[0]) : [];
}
return null;
case 'ressource':
if (_.isObject(data)) {
return data;
}
return null;
case 'related':
case 'relationships':
// TODO:
// - Detect object of relation
// - MtM, OtM: array
// - OtO, MtO: object
2016-01-26 15:35:25 +01:00
if (_.isObject(data) || _.isArray(data) && data.hasOwnProperty(ctx.params.relation)) {
if (_.isArray(data[ctx.params.relation]) && _.size(data[ctx.params.relation]) > 1) {
return data[ctx.params.relation];
}
return _.first(data[ctx.params.relation]) || data[ctx.params.relation];
}
return null;
default:
return 'collection';
}
2016-01-22 15:40:43 +01:00
}
};