mirror of
https://github.com/strapi/strapi.git
synced 2025-07-13 20:11:47 +00:00
258 lines
6.4 KiB
JavaScript
258 lines
6.4 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Module dependencies
|
|
*/
|
|
|
|
// Public node modules.
|
|
const _ = require('lodash');
|
|
const JSONAPISerializer = require('jsonapi-serializer');
|
|
|
|
/**
|
|
* JSON API helper
|
|
*/
|
|
|
|
module.exports = {
|
|
|
|
default: {},
|
|
|
|
/**
|
|
* Set response
|
|
*/
|
|
|
|
set: function (ctx, matchedRoute, actionRoute) {
|
|
const type = this.getType(actionRoute.controller);
|
|
const object = this.getObject(matchedRoute);
|
|
const value = this.verifyAndSetValue(ctx, object);
|
|
|
|
ctx.response.body = this.serialize(ctx, type, value);
|
|
},
|
|
|
|
/**
|
|
* Serialize response with JSON API specification
|
|
*/
|
|
|
|
serialize: function (ctx, type, 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)) {
|
|
const tryFindType = _.first(_.reject(_.map(strapi.models[type].associations, function (relation) {
|
|
return (relation.alias === currentType) ? relation.model || relation.collection : undefined;
|
|
}), _.isUndefined));
|
|
|
|
return _.isUndefined(tryFindType) ? currentType : tryFindType;
|
|
}
|
|
}
|
|
};
|
|
|
|
const PK = this.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);
|
|
}
|
|
|
|
this.includedRelationShips(ctx, toSerialize, type);
|
|
|
|
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] = {
|
|
ref: self.getPK(relation.model),
|
|
attributes: _.keys(strapi.models[type].attributes),
|
|
relationshipLinks: {
|
|
self: ctx.request.origin + ctx.request.url + '/relationships/' + relation.alias,
|
|
related: ctx.request.origin + ctx.request.url
|
|
},
|
|
includedLinks: {
|
|
self: function (data, record) {
|
|
return ctx.request.origin + '/' + relation.model + '/' + record.id;
|
|
}
|
|
}
|
|
};
|
|
break;
|
|
case 'oneToMany':
|
|
case 'manyToMany':
|
|
// Array
|
|
toSerialize[relation.alias] = {
|
|
ref: self.getPK(relation.collection),
|
|
typeForAttribute: relation.collection,
|
|
attributes: _.keys(strapi.models[type].attributes),
|
|
relationshipLinks: {
|
|
self: ctx.request.origin + ctx.request.url + '/relationships/' + relation.alias,
|
|
related: ctx.request.origin + ctx.request.url
|
|
},
|
|
includedLinks: {
|
|
self: function (data, record) {
|
|
return ctx.request.origin + '/' + relation.collection + '/' + record.id;
|
|
}
|
|
}
|
|
};
|
|
break;
|
|
default:
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Verify type of the value
|
|
*/
|
|
|
|
verifyAndSetValue: function (ctx, object) {
|
|
const data = ctx.body;
|
|
|
|
switch (ctx.response.status) {
|
|
case 404:
|
|
ctx.status = 200;
|
|
ctx.body = null;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (object) {
|
|
case 'collection':
|
|
// Collection
|
|
if (_.isArray(data) && _.size(data) > 1) {
|
|
return data;
|
|
} else if (_.isArray(data) && (_.size(data) === 1 || _.size(data) === 0)) {
|
|
return _.isObject(data[0]) ? data[0] : [];
|
|
} else {
|
|
return null;
|
|
}
|
|
break;
|
|
case 'ressource':
|
|
// Ressource
|
|
if (_.isObject(data)) {
|
|
return data;
|
|
} else {
|
|
return null;
|
|
}
|
|
break;
|
|
case 'relationships':
|
|
// TODO:
|
|
// - Detect object of relation
|
|
// - MtM, OtM: array
|
|
// - OtO, MtO: object
|
|
|
|
// Relationships
|
|
if (_.isObject(data) || _.isArray(data)) {
|
|
return data;
|
|
} else {
|
|
return null;
|
|
}
|
|
break;
|
|
case 'related':
|
|
// TODO:
|
|
// - Detect object of relation
|
|
// - MtM, OtM: array
|
|
// - OtO, MtO: object
|
|
|
|
// Related
|
|
if (_.isObject(data) || _.isArray(data)) {
|
|
return data;
|
|
} else {
|
|
return null;
|
|
}
|
|
break;
|
|
default:
|
|
return 'collection';
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Find data object
|
|
*/
|
|
|
|
getObject: function (matchedRoute) {
|
|
// TODO:
|
|
// - Improve way to detect collection/ressource/relationships/related
|
|
|
|
switch (_.size(matchedRoute.regexp.keys)) {
|
|
case 0:
|
|
return 'collection';
|
|
case 1:
|
|
return 'ressource';
|
|
case 2:
|
|
return (matchedRoute.path.indexOf('relationships')) ? 'relationships' : 'related';
|
|
default:
|
|
return 'collection';
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Find data type
|
|
*/
|
|
|
|
getType: function (supposedType) {
|
|
// TODO:
|
|
// - Parse the URL and try to extract useful information to find the type
|
|
|
|
if (strapi.models.hasOwnProperty(supposedType.toLowerCase())) {
|
|
return supposedType.toLowerCase();
|
|
} else {
|
|
return null;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Find primary key
|
|
*/
|
|
|
|
getPK: function (type) {
|
|
if (!strapi.models.hasOwnProperty(type)) {
|
|
return null;
|
|
}
|
|
|
|
const PK = _.findKey(strapi.models[type].attributes, {primaryKey: true});
|
|
|
|
if (!_.isUndefined(PK)) {
|
|
return PK;
|
|
} else if (strapi.models[type].attributes.hasOwnProperty('id')) {
|
|
return 'id';
|
|
} else if (strapi.models[type].attributes.hasOwnProperty('uuid')) {
|
|
return 'uuid';
|
|
}
|
|
|
|
return null;
|
|
}
|
|
};
|