mirror of
https://github.com/strapi/strapi.git
synced 2025-12-28 07:33:17 +00:00
Handle POST method with JSON API request and response
This commit is contained in:
parent
c7049253d6
commit
37b937a4de
@ -6,6 +6,7 @@
|
||||
|
||||
// Public node modules.
|
||||
const _ = require('lodash');
|
||||
const utils = require('../utils/utils');
|
||||
|
||||
/**
|
||||
* JSON API helper
|
||||
@ -19,78 +20,127 @@ module.exports = {
|
||||
* Parse request
|
||||
*/
|
||||
|
||||
parse: function * (ctx, cb) {
|
||||
parse: function * (ctx) {
|
||||
switch (ctx.method.toUpperCase()) {
|
||||
case 'GET':
|
||||
console.log('GET');
|
||||
break;
|
||||
case 'PUT':
|
||||
case 'PATCH':
|
||||
case 'POST':
|
||||
yield this.fetchSchema(ctx, function * (err) {
|
||||
yield cb(err);
|
||||
});
|
||||
try {
|
||||
yield this.fetchSchema(ctx);
|
||||
yield this.formatBody(ctx);
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
break;
|
||||
case 'DELETE':
|
||||
console.log('DELETE');
|
||||
break;
|
||||
default:
|
||||
throw {
|
||||
status: 403,
|
||||
body: 'Invalid HTTP method'
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Format attributes for more simple API
|
||||
*/
|
||||
|
||||
formatBody: function * (ctx) {
|
||||
const body = ctx.request.body;
|
||||
const values = _.assign({}, body.data.attributes);
|
||||
|
||||
_.forEach(body.data.relationships, function (relation, key) {
|
||||
values[key] = _.isArray(relation.data) ? _.map(relation.data, 'id') : relation.data.id;
|
||||
});
|
||||
|
||||
ctx.request.body = values;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch attributes schema
|
||||
*/
|
||||
|
||||
fetchSchema: function * (ctx, cb) {
|
||||
const attributes = ctx.request.body;
|
||||
fetchSchema: function * (ctx) {
|
||||
const body = ctx.request.body;
|
||||
|
||||
if (!attributes.hasOwnProperty('data')) {
|
||||
return yield cb({
|
||||
if (!body.hasOwnProperty('data')) {
|
||||
throw {
|
||||
status: 403,
|
||||
body: 'Missing `data` member'
|
||||
});
|
||||
} else if (!attributes.data.hasOwnProperty('type')) {
|
||||
return yield cb({
|
||||
};
|
||||
} else if (!utils.isRessourceObject(body.data) && ctx.method !== 'POST') {
|
||||
throw {
|
||||
status: 403,
|
||||
body: 'Missing `type` member'
|
||||
});
|
||||
} else if (!strapi.models.hasOwnProperty(attributes.data.type)) {
|
||||
return yield cb({
|
||||
body: 'Invalid ressource object'
|
||||
};
|
||||
} else if (!body.data.hasOwnProperty('type') && ctx.method === 'POST') {
|
||||
throw {
|
||||
status: 403,
|
||||
body: 'Unknow `type` ' + attributes.data.type
|
||||
});
|
||||
body: 'Invalid ressource object'
|
||||
};
|
||||
} else if (!strapi.models.hasOwnProperty(body.data.type)) {
|
||||
throw {
|
||||
status: 403,
|
||||
body: 'Unknow `type` ' + body.data.type
|
||||
};
|
||||
}
|
||||
|
||||
// Extract required attributes
|
||||
const requiredAttributes = _.omit(_.mapValues(strapi.models[attributes.data.type].attributes, function (attr) {
|
||||
return attr.required ? attr : undefined;
|
||||
const requiredAttributes = _.omit(_.mapValues(strapi.models[body.data.type].attributes, function (attr) {
|
||||
return (attr.required && attr.type) ? attr : undefined;
|
||||
}), _.isUndefined);
|
||||
// Identify missing attributes
|
||||
const missingAttributes = _.difference(_.keys(requiredAttributes), _.keys(attributes.data.attributes));
|
||||
const missingAttributes = body.data.hasOwnProperty('attributes') ? _.difference(_.keys(requiredAttributes), _.keys(body.data.attributes)) : null;
|
||||
|
||||
if (!_.isEmpty(missingAttributes)) {
|
||||
return yield cb({
|
||||
throw {
|
||||
status: 403,
|
||||
body: 'Missing required attributes (' + missingAttributes.toString() + ')'
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// Identify required relationships
|
||||
const relationships = _.indexBy(strapi.models[attributes.data.type].associations, 'alias');
|
||||
// Extract required relationships
|
||||
const requiredRelationships = _.intersection(_.keys(requiredAttributes), _.keys(relationships));
|
||||
const requiredRelationships = _.omit(_.mapValues(strapi.models[body.data.type].attributes, function (attr) {
|
||||
return (attr.required && (attr.model || attr.collection)) ? attr : undefined;
|
||||
}), _.isUndefined);
|
||||
// Identify missing relationships
|
||||
const missingRelationships = _.difference(_.keys(requiredRelationships), _.keys(attributes.data.relationships));
|
||||
const missingRelationships = body.data.hasOwnProperty('relationships') ? _.difference(_.keys(requiredRelationships), _.keys(body.data.relationships)) : null;
|
||||
|
||||
if (!_.isEmpty(missingRelationships)) {
|
||||
return yield cb({
|
||||
throw {
|
||||
status: 403,
|
||||
body: 'Missing required relationships (' + missingRelationships.toString() + ')'
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// Looks good
|
||||
yield cb();
|
||||
// Build array of errors
|
||||
if (_.size(requiredRelationships)) {
|
||||
const errors = _.remove(_.flattenDeep(_.map(body.data.relationships, function (relation, key) {
|
||||
if (!relation.hasOwnProperty('data')) {
|
||||
return 'Missing `data` member for relationships ' + relation;
|
||||
} else if (_.isArray(relation.data)) {
|
||||
return _.map(relation.data, function (ressource) {
|
||||
if (!utils.isRessourceObject(ressource)) {
|
||||
return 'Invalid ressource object in relationships ' + key;
|
||||
}
|
||||
});
|
||||
} else if (!utils.isRessourceObject(relation.data)) {
|
||||
return 'Invalid ressource object for relationships ' + key;
|
||||
}
|
||||
})), function (n) {
|
||||
return !_.isUndefined(n);
|
||||
});
|
||||
|
||||
if (!_.isEmpty(errors)) {
|
||||
throw {
|
||||
status: 403,
|
||||
body: errors.toString()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -178,7 +178,7 @@ module.exports = {
|
||||
|
||||
switch (object) {
|
||||
case 'collection':
|
||||
if (_.isArray(data) && _.size(data) > 1) {
|
||||
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]) : [];
|
||||
|
||||
@ -45,7 +45,7 @@ module.exports = function (strapi) {
|
||||
if (this.request.type !== 'application/vnd.api+json') {
|
||||
this.status = 406;
|
||||
this.body = '';
|
||||
} else if (this.request.method === 'GET') {
|
||||
} else {
|
||||
// Intercept only GET request
|
||||
|
||||
// Detect route
|
||||
@ -87,15 +87,14 @@ module.exports = function (strapi) {
|
||||
this.response.status = 406;
|
||||
this.response.body = '';
|
||||
} else {
|
||||
yield request.parse(this, function * (err) {
|
||||
if (err) {
|
||||
return _.assign(self.response, err);
|
||||
}
|
||||
|
||||
try {
|
||||
yield request.parse(this);
|
||||
yield next;
|
||||
});
|
||||
} catch (err) {
|
||||
_.assign(self.response, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
24
lib/configuration/hooks/jsonapi/utils/utils.js
Normal file
24
lib/configuration/hooks/jsonapi/utils/utils.js
Normal file
@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies
|
||||
*/
|
||||
|
||||
// Public node modules.
|
||||
const _ = require('lodash');
|
||||
|
||||
/**
|
||||
* JSON API utils
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
|
||||
/**
|
||||
* Verify ressource object
|
||||
*/
|
||||
|
||||
isRessourceObject: function (object) {
|
||||
return _.isObject(object) && object.hasOwnProperty('id') && object.hasOwnProperty('type');
|
||||
}
|
||||
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user