078060abdc
* Installed @tryghost/members-ssr@0.2.1 refs https://github.com/TryGhost/Members/issues/38 This updates allows for dynamic access of the membersApi, which will be used in future when replacing the membersApi instance with a newly configured one. * Set the membersApiInstance logger to use common.logging refs https://github.com/TryGhost/Members/issues/38 Passes the Ghost logger to the members api, so that we can keep an eye on errors produced by the api. * Refactored memberService use to always use getter refs https://github.com/TryGhost/Members/issues/38 This will allow us to switch out the membersApi and the consumers of it to have the updated reference by going through a getter. * Installed @tryghost/members-api@0.3.0 refs https://github.com/TryGhost/Members/issues/38 Adds support for setting the logger * Uninstalled stripe@7.0.0 refs https://github.com/TryGhost/Members/issues/38 The stripe module is now a dep of members-api, as it should be * Updated members service to reconfigure settings refs https://github.com/TryGhost/Members/issues/38 Previously we were unable to stop an invalidly configured members api instance, now that we create a new instance, we can wait for the ready or error event and only switch it out then. |
||
---|---|---|
.. | ||
shared | ||
v0.1 | ||
v2 | ||
index.js | ||
README.md |
API Versioning
Ghost supports multiple API versions. Each version lives in a separate folder e.g. api/v0.1, api/v2. Next to the API folders there is a shared folder, which contains shared code, which all API versions use.
NOTE: v0.1 is deprecated and we won't touch the shared folder at all. The v0.1 folder contains the API layer which we have used since Ghost was born.
Stages
Each request goes through the following stages:
- input validation
- input serialisation
- permissions
- query
- output serialisation
The framework we are building pipes a request through these stages in respect of the API controller configuration.
Frame
Is a class, which holds all the information for request processing. We pass this instance by reference. Each function can modify the original instance. No need to return the class instance.
Structure
{
original: Object,
options: Object,
data: Object,
user: Object,
file: Object,
files: Array
}
Example
{
original: {
include: 'tags'
},
options: {
withRelated: ['tags']
},
data: {
posts: []
}
}
API Controller
A controller is no longer just a function, it's a set of configurations.
Structure
edit: function || object
edit: {
headers: object,
options: Array,
data: Array,
validation: object | function,
permissions: boolean | object | function,
query: function
}
Examples
edit: {
headers: {
cacheInvalidate: true
},
// Allowed url/query params
options: ['include']
// Url/query param validation configuration
validation: {
options: {
include: {
required: true,
values: ['tags']
}
}
},
permissions: true,
// Returns a model response!
query(frame) {
return models.Post.edit(frame.data, frame.options);
}
}
read: {
// Allowed url/query params, which will be remembered inside `frame.data`
// This is helpful for READ requests e.g. `model.findOne(frame.data, frame.options)`.
// Our model layer requires sending the where clauses as first parameter.
data: ['slug']
validation: {
data: {
slug: {
values: ['eins']
}
}
},
permissions: true,
query(frame) {
return models.Post.findOne(frame.data, frame.options);
}
}
edit: {
validation() {
// custom validation, skip framework
},
permissions: {
unsafeAttrs: ['author']
},
query(frame) {
return models.Post.edit(frame.data, frame.options);
}
}