From 2da3adc1bed6a439eb325c6954f305787eac9530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Georget?= Date: Mon, 8 Feb 2016 12:07:58 +0100 Subject: [PATCH] Handle relationships update --- .../hooks/jsonapi/helpers/request.js | 76 ++++++++++++++++--- .../hooks/jsonapi/helpers/response.js | 2 +- lib/configuration/hooks/jsonapi/index.js | 11 +-- .../hooks/jsonapi/utils/utils.js | 14 +++- 4 files changed, 84 insertions(+), 19 deletions(-) diff --git a/lib/configuration/hooks/jsonapi/helpers/request.js b/lib/configuration/hooks/jsonapi/helpers/request.js index 386d9da049..8c8dc5998b 100644 --- a/lib/configuration/hooks/jsonapi/helpers/request.js +++ b/lib/configuration/hooks/jsonapi/helpers/request.js @@ -35,7 +35,6 @@ module.exports = { // HTTP methods allowed switch (this.default.method) { case 'GET': - // Nothing to do try { yield this.fetchQuery(ctx); } catch (err) { @@ -44,20 +43,27 @@ module.exports = { break; case 'PATCH': case 'POST': - // TODO: - // - Detect relationships edition or addition - // - Fetch and format body try { - yield this.fetchSchema(ctx); - yield this.formatBody(ctx); + if (utils.getObject(utils.matchedRoute(ctx)) === 'relationships') { + yield this.fetchRelationRequest(ctx); + yield this.formatRelationBody(ctx); + } else { + yield this.fetchSchema(ctx); + yield this.formatBody(ctx); + } } catch (err) { throw err; } break; case 'DELETE': - // TODO: - // - Detect relationships deletion - // - Fetch and format body + if (utils.getObject(utils.matchedRoute(ctx)) === 'relationships') { + try { + yield this.fetchRelationRequest(ctx); + yield this.formatRelationBody(ctx); + } catch (err) { + throw err; + } + } break; default: throw { @@ -69,6 +75,58 @@ module.exports = { } }, + /** + * Format attributes for relationships request to get more simple API + */ + + formatRelationBody: function * (ctx) { + ctx.request.body = _.map(ctx.request.body.data, 'id'); + }, + + /** + * Fetch request for relationships + */ + + fetchRelationRequest: function * (ctx) { + const body = ctx.request.body; + + if (!body.hasOwnProperty('data')) { + throw { + status: 403, + body: { + message: 'Missing `data` member' + } + }; + } else if (_.isPlainObject(body.data) && !utils.isRessourceObject(body.data)) { + throw { + status: 403, + body: { + message: 'Invalid ressource object' + } + }; + } else if (_.isArray(body.data)) { + const errors = _.remove(_.map(body.data, function (n, position) { + if (!utils.isRessourceObject(n) || _.isUndefined(utils.getType(ctx, _.get(n, 'type')))) { + return { + position: position, + message: 'Invalid ressource object or unknow type' + }; + } + }), function (n) { + return !_.isUndefined(n); + }); + + if (!_.isEmpty(errors)) { + throw { + status: 403, + body: { + message: errors + } + }; + } + } + }, + /** * Format attributes for more simple API */ diff --git a/lib/configuration/hooks/jsonapi/helpers/response.js b/lib/configuration/hooks/jsonapi/helpers/response.js index 96f65ca16f..a285b8db8c 100644 --- a/lib/configuration/hooks/jsonapi/helpers/response.js +++ b/lib/configuration/hooks/jsonapi/helpers/response.js @@ -163,7 +163,7 @@ module.exports = { }); // TODO: - // - Execute some requests to get first, lastest, previous and next record + // - Call request to get first, latest, previous and next record switch (object) { default: diff --git a/lib/configuration/hooks/jsonapi/index.js b/lib/configuration/hooks/jsonapi/index.js index a9354fc7da..923cfeee2b 100644 --- a/lib/configuration/hooks/jsonapi/index.js +++ b/lib/configuration/hooks/jsonapi/index.js @@ -10,6 +10,7 @@ const _ = require('lodash'); // Local Strapi dependencies. const request = require('./helpers/request'); const response = require('./helpers/response'); +const utils = require('./utils/utils'); /** * JSON API hook @@ -24,8 +25,6 @@ module.exports = function (strapi) { initialize: function (cb) { function * _interceptor(next) { - const self = this; - // Wait for downstream middleware/handlers to execute to build the response yield next; @@ -42,15 +41,11 @@ module.exports = function (strapi) { // Intercept success requests // Detect route - const matchedRoute = _.find(strapi.router.stack, function (stack) { - if (new RegExp(stack.regexp).test(self.request.url) && _.includes(stack.methods, self.request.method.toUpperCase())) { - return stack; - } - }); + const matchedRoute = utils.matchedRoute(this); if (!_.isUndefined(matchedRoute)) { // Handlers set the response body - const actionRoute = strapi.config.routes[self.request.method.toUpperCase() + ' ' + matchedRoute.path]; + const actionRoute = strapi.config.routes[this.request.method.toUpperCase() + ' ' + matchedRoute.path]; if (!_.isUndefined(actionRoute)) { response.set(this, matchedRoute, actionRoute); diff --git a/lib/configuration/hooks/jsonapi/utils/utils.js b/lib/configuration/hooks/jsonapi/utils/utils.js index 802f47ece0..95d6aa3357 100644 --- a/lib/configuration/hooks/jsonapi/utils/utils.js +++ b/lib/configuration/hooks/jsonapi/utils/utils.js @@ -54,7 +54,7 @@ module.exports = { getType: function (ctx, supposedType) { // Relationships or related ressource - if (strapi.models.hasOwnProperty(supposedType.toLowerCase()) && ctx.params.hasOwnProperty('relation')) { + if (strapi.models.hasOwnProperty(supposedType.toLowerCase()) && ctx.params.hasOwnProperty('relation') && ctx.method === 'GET') { return _.first(_.reject(_.map(strapi.models[supposedType.toLowerCase()].associations, function (relation) { return (ctx.params.hasOwnProperty('relation') && ctx.params.relation === relation.alias) ? relation.model || relation.collection : undefined; }), _.isUndefined)); @@ -96,6 +96,18 @@ module.exports = { } return null; + }, + + /** + * Find router object for matched route + */ + + matchedRoute: function (ctx) { + return _.find(strapi.router.stack, function (stack) { + if (new RegExp(stack.regexp).test(ctx.request.url) && _.includes(stack.methods, ctx.request.method.toUpperCase())) { + return stack; + } + }); } };