Ensured defaults when creating resources

no issue

- the model & api layer suffered from missing fields when creating resources
- usually there is only a handful of fields which are required to insert a resource
- the other fields are nullable and/or get defaults assigned
- the API only returned the configured default fields and the fields you have sent to the API
  - this resulted in a response with missing fields
- if you have listend on "created" event, the same happend
  - you received a model with missing fields
- we now set the undefined fields to null on purpose to ensure a full model for both cases

@NOTE:
There is no endpoint to serve webhooks (not for v0.1, not for v2).
Exposing the secret is required if an integration fetches it's api keys and it's webhooks.
The secret is currently un-used and not implemented.
This commit is contained in:
kirrg001 2019-02-07 20:01:47 +01:00
parent 52a482cba8
commit b25da62cca
7 changed files with 25 additions and 41 deletions

View File

@ -328,9 +328,27 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
}
}
model._changed = _.cloneDeep(model.changed);
return Promise.resolve(this.onValidate(model, attr, options))
.then(() => {
/**
* @NOTE:
*
* The API requires only specific attributes to send. If we don't set the rest explicitly to null,
* we end up in a situation that on "created" events the field set is incomplete, which is super confusing
* and hard to work with if you trigger internal events, which rely on full field set. This ensures consistency.
*
* @NOTE:
*
* Happens after validation to ensure we don't set fields which are not nullable on db level.
*/
_.each(Object.keys(schema.tables[this.tableName]), (columnKey) => {
if (model.get(columnKey) === undefined) {
model.set(columnKey, null);
}
});
return Promise.resolve(this.onValidate(model, attr, options));
model._changed = _.cloneDeep(model.changed);
});
},
/**

View File

@ -99,13 +99,8 @@ describe('Tag API', function () {
should.exist(jsonResponse);
should.exist(jsonResponse.tags);
jsonResponse.tags.should.have.length(1);
// @TODO: model layer has no defaults for these properties
localUtils.API.checkResponse(jsonResponse.tags[0], 'tag', ['url'], [
'feature_image',
'meta_description',
'meta_title',
'parent'
]);
localUtils.API.checkResponse(jsonResponse.tags[0], 'tag', ['url']);
testUtils.API.isISO8601(jsonResponse.tags[0].created_at).should.be.true();
});
});

View File

@ -61,14 +61,6 @@ const expectedProperties = {
,
webhook: _(schema.webhooks)
.keys()
.without(
'name',
'last_triggered_at',
'last_triggered_error',
'last_triggered_status',
'secret',
'integration_id'
)
};
_.each(expectedProperties, (value, key) => {

View File

@ -44,7 +44,7 @@ describe('Webhooks API', function () {
should.exist(jsonResponse.webhooks);
localUtils.API.checkResponse(jsonResponse.webhooks[0], 'webhook', ['name', 'secret']);
localUtils.API.checkResponse(jsonResponse.webhooks[0], 'webhook');
jsonResponse.webhooks[0].event.should.equal(webhookData.event);
jsonResponse.webhooks[0].target_url.should.equal(webhookData.target_url);

View File

@ -88,13 +88,8 @@ describe('Tag API', function () {
should.exist(jsonResponse);
should.exist(jsonResponse.tags);
jsonResponse.tags.should.have.length(1);
// @TODO: model layer has no defaults for these properties
localUtils.API.checkResponse(jsonResponse.tags[0], 'tag', null, [
'feature_image',
'meta_description',
'meta_title',
'parent'
]);
localUtils.API.checkResponse(jsonResponse.tags[0], 'tag');
testUtils.API.isISO8601(jsonResponse.tags[0].created_at).should.be.true();
});
});

View File

@ -72,14 +72,6 @@ const expectedProperties = {
webhook: {
default: _(schema.webhooks)
.keys()
.without(
'name',
'last_triggered_at',
'last_triggered_error',
'last_triggered_status',
'secret',
'integration_id'
)
.value()
}
};

View File

@ -58,14 +58,6 @@ const expectedProperties = {
,
webhook: _(schema.webhooks)
.keys()
.without(
'name',
'last_triggered_at',
'last_triggered_error',
'last_triggered_status',
'secret',
'integration_id'
)
};
_.each(expectedProperties, (value, key) => {