Cached api controller pipelines (#19880)
ref ENG-761 ref https://linear.app/tryghost/issue/ENG-761 Creating these pipelines is expensive, and we don't want to do it repeatedly for the same controller. Adding caching should reduce the amount of time spent setting up pipelines for each usage of the `get` helper.
This commit is contained in:
parent
a67342b06a
commit
3f27ca5c00
@ -160,6 +160,8 @@ const STAGES = {
|
||||
}
|
||||
};
|
||||
|
||||
const controllerMap = new Map();
|
||||
|
||||
/**
|
||||
* @description The pipeline runs the request through all stages (validation, serialisation, permissions).
|
||||
*
|
||||
@ -180,12 +182,16 @@ const STAGES = {
|
||||
* @return {Object}
|
||||
*/
|
||||
const pipeline = (apiController, apiUtils, apiType) => {
|
||||
if (controllerMap.has(apiController)) {
|
||||
return controllerMap.get(apiController);
|
||||
}
|
||||
|
||||
const keys = Object.keys(apiController);
|
||||
const docName = apiController.docName;
|
||||
|
||||
// CASE: api controllers are objects with configuration.
|
||||
// We have to ensure that we expose a functional interface e.g. `api.posts.add` has to be available.
|
||||
return keys.reduce((obj, method) => {
|
||||
const result = keys.reduce((obj, method) => {
|
||||
const apiImpl = _.cloneDeep(apiController)[method];
|
||||
|
||||
Object.freeze(apiImpl.headers);
|
||||
@ -267,6 +273,10 @@ const pipeline = (apiController, apiUtils, apiType) => {
|
||||
Object.assign(obj[method], apiImpl);
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
controllerMap.set(apiController, result);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
module.exports = pipeline;
|
||||
|
@ -33,8 +33,8 @@ describe('Frontend behavior tests', function () {
|
||||
|
||||
beforeEach(function () {
|
||||
sinon.stub(themeEngine.getActive(), 'config').withArgs('posts_per_page').returns(2);
|
||||
const postsAPI = require('../../../core/server/api/endpoints/posts-public');
|
||||
postSpy = sinon.spy(postsAPI.browse, 'query');
|
||||
const postsAPI = require('../../../core/server/api/endpoints').postsPublic;
|
||||
postSpy = sinon.spy(postsAPI, 'browse');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
@ -143,22 +143,20 @@ describe('Frontend behavior tests', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('serve tag', function () {
|
||||
it('serve tag', async function () {
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/tag/bacon/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return localUtils.mockExpress.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('tag');
|
||||
const response = await localUtils.mockExpress.invoke(app, req);
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('tag');
|
||||
|
||||
postSpy.args[0][0].options.filter.should.eql('(tags:\'bacon\'+tags.visibility:public)+type:post');
|
||||
postSpy.args[0][0].options.page.should.eql(1);
|
||||
postSpy.args[0][0].options.limit.should.eql(2);
|
||||
});
|
||||
postSpy.args[0][0].filter.should.eql('tags:\'bacon\'+tags.visibility:public');
|
||||
postSpy.args[0][0].page.should.eql(1);
|
||||
postSpy.args[0][0].limit.should.eql(2);
|
||||
});
|
||||
|
||||
it('serve tag rss', function () {
|
||||
|
Loading…
Reference in New Issue
Block a user