Refactoring: API/Model layer - pass options object
See original GitHub issueProblem description
There are two problems.
API layer and pipeline
If you take a look at this commit, you will see that the way our pipeline tooling works, clashes with how our API layer works. The API layer always needs access to the modified options object. These modifications happen in stages e.g. permissions are getting added. Furthermore, the pipeline tooling requires us to return the options in each function call, see. Furthermore, it’s a mixed design, because we pass an argument by reference, we modify it, but we have to return it. That is super confusing. Either you get an argument, you create your own object, eat from the argument and return the new object or you follow the pattern of object modification.
something(options) {
options.a = 'lol';
returns options;
}
beautiful(options) {
assert.true(options.a);
returns options;
}
pipeline([something, beautiful], options)
Model layer and the access plugin
The model layer uses two different techniques to determine the permissions of a model query. The access rules plugin and the direct check. The access plugin requires us to pass the permission context into the .forge
function, which instantiates a new model. Doing that allows us to use a helper function like isPublicContext
. Right now, it’s almost never used and we have permission checks in the whole system, not just in the model layer. Plus bookshelf follows the concept of the options pattern very strong. You always have to pass your options into function calls e.g. .fetch(options)
. The outcome of this is that on each model hook we are able to access our options. So having access to this._context, is not useful, because we can access the options anyway in each function.
This is how the options object get’s passed through the system
- options object is created in our API HTTP wrapper
- passed into API and see
- request body get’s added if available
- permissions are added
- forwarded to model
Questions
What is the best way to pass it around? How to keep track of the API options object? Get rid of .forge?
Solutions
Replace pipeline in the API layer
This requires us to make even more usage of the options pattern.
permissions(options) {
options.context = {...};
}
query(options) {
models.Post.edit(options)
.then(function(updatedModel) {
options.response = updatedModel;
});
}
pipeline([something, beautiful], options)
.then(function(options) {
});
The full options object would look like this:
{
context/permissions: {},
data: {},
params: {},
response: {},
transacting: {}
}
Remove the access plugin
Remove the plugin for now and use direct context checks. The future goal here is to make the context object very powerful e.g. by creating a class e.g. new Context()
, which is passes within the options object, which then allows you to call options.context.isPublic()
.
Tasks
- read idea from slack https://ghost.slack.com/archives/C02G9E68C/p1516732377000504
- remove access plugin
- replace pipeline
- change how we pass the incoming request params and body (use the options object)
- change how we return the model response
Future
We would like to write an issue for transforming the context object into a class. And another issue about who is responsible to calling toJSON
of a model - we have very heavy mixture of this concept.
Issue Analytics
- State:
- Created 6 years ago
- Comments:7 (5 by maintainers)
Top GitHub Comments
@kirrg001 No unfortunately I don’t think so 😕 Sorry for not communicating this before. Me and my friends did some work which can be seen in these pull requests.
We replaced the pipeline in most parts of the api with the new “sequential.js” which in comparison to the old “pipeline.js” does not return the options object to the next task in the pipeline. Instead we add parameters that is needed later in the execution to the options object like we discussed.
Closing this issue in favor of #9866.