Ghost/ghost/api-framework/test/pipeline.test.js

337 lines
13 KiB
JavaScript
Raw Normal View History

const errors = require('@tryghost/errors');
Added tiny framework to support multiple API versions (#9933) refs #9326, refs #9866 **ATTENTION: This is the first iteration. Bugs are expected.** Main Goals: - add support for multiple API versions. - do not touch v0.1 implementation - do not break v0.1 ## Problems with the existing v0.1 implementation 1. It tried to be generic and helpful, but it was a mixture of generic and explicit logic living in basically two files: utils.js and index.js. 2. Supporting multiple api versions means, you want to have as less as possible code per API version. With v0.1 it is impossible to reduce the API controller implementation. ---- This commit adds three things: 1. The tiny framework with well-defined API stages. 2. An example implementation of serving static pages via /pages for the content v2 API. 3. Unit tests to prove that the API framework works in general. ## API Stages - validation - input serialization - permissions - query - output serialization Each request should go through these stages. It is possible to disable stages, but it's not recommended. The code for each stage will either live in a shared folder or in the API version itself. It depends how API specific the validation or serialization is. Depends on the use case. We should add a specific API validator or serializer if the use case is API format specific. We should put everything else to shared. The goal is to add as much as possible into the shared API layer to reduce the logic per API version. --- Serializers and validators can be added: - for each request - for specific controllers - for specific actions --- There is room for improvements/extensions: 1. Remove http header configuration from the API controller, because the API controller should not know about http - decouple. 2. Put permissions helpers into shared. I've just extracted and capsulated the permissions helpers into a single file for now. It had no priority. The focus was on the framework itself. etc. --- You can find more information about it in the API README.md (api/README.md) - e.g. find more information about the structure - e.g. example controllers The docs are not perfect. We will improve the docs in the next two weeks. --- Upcoming tasks: - prepare test env to test multiple API versions - copy over the controllers from v0.1 to v2 - adapt the v2 express app to use the v2 controllers
2018-10-05 01:50:45 +03:00
const should = require('should');
const sinon = require('sinon');
const shared = require('../');
Added tiny framework to support multiple API versions (#9933) refs #9326, refs #9866 **ATTENTION: This is the first iteration. Bugs are expected.** Main Goals: - add support for multiple API versions. - do not touch v0.1 implementation - do not break v0.1 ## Problems with the existing v0.1 implementation 1. It tried to be generic and helpful, but it was a mixture of generic and explicit logic living in basically two files: utils.js and index.js. 2. Supporting multiple api versions means, you want to have as less as possible code per API version. With v0.1 it is impossible to reduce the API controller implementation. ---- This commit adds three things: 1. The tiny framework with well-defined API stages. 2. An example implementation of serving static pages via /pages for the content v2 API. 3. Unit tests to prove that the API framework works in general. ## API Stages - validation - input serialization - permissions - query - output serialization Each request should go through these stages. It is possible to disable stages, but it's not recommended. The code for each stage will either live in a shared folder or in the API version itself. It depends how API specific the validation or serialization is. Depends on the use case. We should add a specific API validator or serializer if the use case is API format specific. We should put everything else to shared. The goal is to add as much as possible into the shared API layer to reduce the logic per API version. --- Serializers and validators can be added: - for each request - for specific controllers - for specific actions --- There is room for improvements/extensions: 1. Remove http header configuration from the API controller, because the API controller should not know about http - decouple. 2. Put permissions helpers into shared. I've just extracted and capsulated the permissions helpers into a single file for now. It had no priority. The focus was on the framework itself. etc. --- You can find more information about it in the API README.md (api/README.md) - e.g. find more information about the structure - e.g. example controllers The docs are not perfect. We will improve the docs in the next two weeks. --- Upcoming tasks: - prepare test env to test multiple API versions - copy over the controllers from v0.1 to v2 - adapt the v2 express app to use the v2 controllers
2018-10-05 01:50:45 +03:00
describe('Pipeline', function () {
Added tiny framework to support multiple API versions (#9933) refs #9326, refs #9866 **ATTENTION: This is the first iteration. Bugs are expected.** Main Goals: - add support for multiple API versions. - do not touch v0.1 implementation - do not break v0.1 ## Problems with the existing v0.1 implementation 1. It tried to be generic and helpful, but it was a mixture of generic and explicit logic living in basically two files: utils.js and index.js. 2. Supporting multiple api versions means, you want to have as less as possible code per API version. With v0.1 it is impossible to reduce the API controller implementation. ---- This commit adds three things: 1. The tiny framework with well-defined API stages. 2. An example implementation of serving static pages via /pages for the content v2 API. 3. Unit tests to prove that the API framework works in general. ## API Stages - validation - input serialization - permissions - query - output serialization Each request should go through these stages. It is possible to disable stages, but it's not recommended. The code for each stage will either live in a shared folder or in the API version itself. It depends how API specific the validation or serialization is. Depends on the use case. We should add a specific API validator or serializer if the use case is API format specific. We should put everything else to shared. The goal is to add as much as possible into the shared API layer to reduce the logic per API version. --- Serializers and validators can be added: - for each request - for specific controllers - for specific actions --- There is room for improvements/extensions: 1. Remove http header configuration from the API controller, because the API controller should not know about http - decouple. 2. Put permissions helpers into shared. I've just extracted and capsulated the permissions helpers into a single file for now. It had no priority. The focus was on the framework itself. etc. --- You can find more information about it in the API README.md (api/README.md) - e.g. find more information about the structure - e.g. example controllers The docs are not perfect. We will improve the docs in the next two weeks. --- Upcoming tasks: - prepare test env to test multiple API versions - copy over the controllers from v0.1 to v2 - adapt the v2 express app to use the v2 controllers
2018-10-05 01:50:45 +03:00
afterEach(function () {
sinon.restore();
Added tiny framework to support multiple API versions (#9933) refs #9326, refs #9866 **ATTENTION: This is the first iteration. Bugs are expected.** Main Goals: - add support for multiple API versions. - do not touch v0.1 implementation - do not break v0.1 ## Problems with the existing v0.1 implementation 1. It tried to be generic and helpful, but it was a mixture of generic and explicit logic living in basically two files: utils.js and index.js. 2. Supporting multiple api versions means, you want to have as less as possible code per API version. With v0.1 it is impossible to reduce the API controller implementation. ---- This commit adds three things: 1. The tiny framework with well-defined API stages. 2. An example implementation of serving static pages via /pages for the content v2 API. 3. Unit tests to prove that the API framework works in general. ## API Stages - validation - input serialization - permissions - query - output serialization Each request should go through these stages. It is possible to disable stages, but it's not recommended. The code for each stage will either live in a shared folder or in the API version itself. It depends how API specific the validation or serialization is. Depends on the use case. We should add a specific API validator or serializer if the use case is API format specific. We should put everything else to shared. The goal is to add as much as possible into the shared API layer to reduce the logic per API version. --- Serializers and validators can be added: - for each request - for specific controllers - for specific actions --- There is room for improvements/extensions: 1. Remove http header configuration from the API controller, because the API controller should not know about http - decouple. 2. Put permissions helpers into shared. I've just extracted and capsulated the permissions helpers into a single file for now. It had no priority. The focus was on the framework itself. etc. --- You can find more information about it in the API README.md (api/README.md) - e.g. find more information about the structure - e.g. example controllers The docs are not perfect. We will improve the docs in the next two weeks. --- Upcoming tasks: - prepare test env to test multiple API versions - copy over the controllers from v0.1 to v2 - adapt the v2 express app to use the v2 controllers
2018-10-05 01:50:45 +03:00
});
describe('stages', function () {
describe('validation', function () {
describe('input', function () {
beforeEach(function () {
sinon.stub(shared.validators.handle, 'input').resolves();
Added tiny framework to support multiple API versions (#9933) refs #9326, refs #9866 **ATTENTION: This is the first iteration. Bugs are expected.** Main Goals: - add support for multiple API versions. - do not touch v0.1 implementation - do not break v0.1 ## Problems with the existing v0.1 implementation 1. It tried to be generic and helpful, but it was a mixture of generic and explicit logic living in basically two files: utils.js and index.js. 2. Supporting multiple api versions means, you want to have as less as possible code per API version. With v0.1 it is impossible to reduce the API controller implementation. ---- This commit adds three things: 1. The tiny framework with well-defined API stages. 2. An example implementation of serving static pages via /pages for the content v2 API. 3. Unit tests to prove that the API framework works in general. ## API Stages - validation - input serialization - permissions - query - output serialization Each request should go through these stages. It is possible to disable stages, but it's not recommended. The code for each stage will either live in a shared folder or in the API version itself. It depends how API specific the validation or serialization is. Depends on the use case. We should add a specific API validator or serializer if the use case is API format specific. We should put everything else to shared. The goal is to add as much as possible into the shared API layer to reduce the logic per API version. --- Serializers and validators can be added: - for each request - for specific controllers - for specific actions --- There is room for improvements/extensions: 1. Remove http header configuration from the API controller, because the API controller should not know about http - decouple. 2. Put permissions helpers into shared. I've just extracted and capsulated the permissions helpers into a single file for now. It had no priority. The focus was on the framework itself. etc. --- You can find more information about it in the API README.md (api/README.md) - e.g. find more information about the structure - e.g. example controllers The docs are not perfect. We will improve the docs in the next two weeks. --- Upcoming tasks: - prepare test env to test multiple API versions - copy over the controllers from v0.1 to v2 - adapt the v2 express app to use the v2 controllers
2018-10-05 01:50:45 +03:00
});
it('do it yourself', function () {
const apiUtils = {};
const apiConfig = {};
const apiImpl = {
validation: sinon.stub().resolves('response')
Added tiny framework to support multiple API versions (#9933) refs #9326, refs #9866 **ATTENTION: This is the first iteration. Bugs are expected.** Main Goals: - add support for multiple API versions. - do not touch v0.1 implementation - do not break v0.1 ## Problems with the existing v0.1 implementation 1. It tried to be generic and helpful, but it was a mixture of generic and explicit logic living in basically two files: utils.js and index.js. 2. Supporting multiple api versions means, you want to have as less as possible code per API version. With v0.1 it is impossible to reduce the API controller implementation. ---- This commit adds three things: 1. The tiny framework with well-defined API stages. 2. An example implementation of serving static pages via /pages for the content v2 API. 3. Unit tests to prove that the API framework works in general. ## API Stages - validation - input serialization - permissions - query - output serialization Each request should go through these stages. It is possible to disable stages, but it's not recommended. The code for each stage will either live in a shared folder or in the API version itself. It depends how API specific the validation or serialization is. Depends on the use case. We should add a specific API validator or serializer if the use case is API format specific. We should put everything else to shared. The goal is to add as much as possible into the shared API layer to reduce the logic per API version. --- Serializers and validators can be added: - for each request - for specific controllers - for specific actions --- There is room for improvements/extensions: 1. Remove http header configuration from the API controller, because the API controller should not know about http - decouple. 2. Put permissions helpers into shared. I've just extracted and capsulated the permissions helpers into a single file for now. It had no priority. The focus was on the framework itself. etc. --- You can find more information about it in the API README.md (api/README.md) - e.g. find more information about the structure - e.g. example controllers The docs are not perfect. We will improve the docs in the next two weeks. --- Upcoming tasks: - prepare test env to test multiple API versions - copy over the controllers from v0.1 to v2 - adapt the v2 express app to use the v2 controllers
2018-10-05 01:50:45 +03:00
};
const frame = {};
return shared.pipeline.STAGES.validation.input(apiUtils, apiConfig, apiImpl, frame)
.then((response) => {
response.should.eql('response');
apiImpl.validation.calledOnce.should.be.true();
shared.validators.handle.input.called.should.be.false();
});
});
it('default', function () {
const apiUtils = {
validators: {
input: {
posts: {}
}
}
};
const apiConfig = {
docName: 'posts'
};
const apiImpl = {
options: ['include'],
validation: {
options: {
include: {
required: true
}
}
}
};
const frame = {
options: {}
};
return shared.pipeline.STAGES.validation.input(apiUtils, apiConfig, apiImpl, frame)
.then(() => {
shared.validators.handle.input.calledOnce.should.be.true();
shared.validators.handle.input.calledWith(
{
docName: 'posts',
options: {
include: {
required: true
}
}
},
{
posts: {}
},
{
options: {}
}).should.be.true();
});
});
});
});
describe('permissions', function () {
let apiUtils;
beforeEach(function () {
apiUtils = {
permissions: {
handle: sinon.stub().resolves()
Added tiny framework to support multiple API versions (#9933) refs #9326, refs #9866 **ATTENTION: This is the first iteration. Bugs are expected.** Main Goals: - add support for multiple API versions. - do not touch v0.1 implementation - do not break v0.1 ## Problems with the existing v0.1 implementation 1. It tried to be generic and helpful, but it was a mixture of generic and explicit logic living in basically two files: utils.js and index.js. 2. Supporting multiple api versions means, you want to have as less as possible code per API version. With v0.1 it is impossible to reduce the API controller implementation. ---- This commit adds three things: 1. The tiny framework with well-defined API stages. 2. An example implementation of serving static pages via /pages for the content v2 API. 3. Unit tests to prove that the API framework works in general. ## API Stages - validation - input serialization - permissions - query - output serialization Each request should go through these stages. It is possible to disable stages, but it's not recommended. The code for each stage will either live in a shared folder or in the API version itself. It depends how API specific the validation or serialization is. Depends on the use case. We should add a specific API validator or serializer if the use case is API format specific. We should put everything else to shared. The goal is to add as much as possible into the shared API layer to reduce the logic per API version. --- Serializers and validators can be added: - for each request - for specific controllers - for specific actions --- There is room for improvements/extensions: 1. Remove http header configuration from the API controller, because the API controller should not know about http - decouple. 2. Put permissions helpers into shared. I've just extracted and capsulated the permissions helpers into a single file for now. It had no priority. The focus was on the framework itself. etc. --- You can find more information about it in the API README.md (api/README.md) - e.g. find more information about the structure - e.g. example controllers The docs are not perfect. We will improve the docs in the next two weeks. --- Upcoming tasks: - prepare test env to test multiple API versions - copy over the controllers from v0.1 to v2 - adapt the v2 express app to use the v2 controllers
2018-10-05 01:50:45 +03:00
}
};
});
it('key is missing', function () {
const apiConfig = {};
const apiImpl = {};
const frame = {};
return shared.pipeline.STAGES.permissions(apiUtils, apiConfig, apiImpl, frame)
.then(Promise.reject)
.catch((err) => {
(err instanceof errors.IncorrectUsageError).should.be.true();
Added tiny framework to support multiple API versions (#9933) refs #9326, refs #9866 **ATTENTION: This is the first iteration. Bugs are expected.** Main Goals: - add support for multiple API versions. - do not touch v0.1 implementation - do not break v0.1 ## Problems with the existing v0.1 implementation 1. It tried to be generic and helpful, but it was a mixture of generic and explicit logic living in basically two files: utils.js and index.js. 2. Supporting multiple api versions means, you want to have as less as possible code per API version. With v0.1 it is impossible to reduce the API controller implementation. ---- This commit adds three things: 1. The tiny framework with well-defined API stages. 2. An example implementation of serving static pages via /pages for the content v2 API. 3. Unit tests to prove that the API framework works in general. ## API Stages - validation - input serialization - permissions - query - output serialization Each request should go through these stages. It is possible to disable stages, but it's not recommended. The code for each stage will either live in a shared folder or in the API version itself. It depends how API specific the validation or serialization is. Depends on the use case. We should add a specific API validator or serializer if the use case is API format specific. We should put everything else to shared. The goal is to add as much as possible into the shared API layer to reduce the logic per API version. --- Serializers and validators can be added: - for each request - for specific controllers - for specific actions --- There is room for improvements/extensions: 1. Remove http header configuration from the API controller, because the API controller should not know about http - decouple. 2. Put permissions helpers into shared. I've just extracted and capsulated the permissions helpers into a single file for now. It had no priority. The focus was on the framework itself. etc. --- You can find more information about it in the API README.md (api/README.md) - e.g. find more information about the structure - e.g. example controllers The docs are not perfect. We will improve the docs in the next two weeks. --- Upcoming tasks: - prepare test env to test multiple API versions - copy over the controllers from v0.1 to v2 - adapt the v2 express app to use the v2 controllers
2018-10-05 01:50:45 +03:00
apiUtils.permissions.handle.called.should.be.false();
});
});
it('do it yourself', function () {
const apiConfig = {};
const apiImpl = {
permissions: sinon.stub().resolves('lol')
Added tiny framework to support multiple API versions (#9933) refs #9326, refs #9866 **ATTENTION: This is the first iteration. Bugs are expected.** Main Goals: - add support for multiple API versions. - do not touch v0.1 implementation - do not break v0.1 ## Problems with the existing v0.1 implementation 1. It tried to be generic and helpful, but it was a mixture of generic and explicit logic living in basically two files: utils.js and index.js. 2. Supporting multiple api versions means, you want to have as less as possible code per API version. With v0.1 it is impossible to reduce the API controller implementation. ---- This commit adds three things: 1. The tiny framework with well-defined API stages. 2. An example implementation of serving static pages via /pages for the content v2 API. 3. Unit tests to prove that the API framework works in general. ## API Stages - validation - input serialization - permissions - query - output serialization Each request should go through these stages. It is possible to disable stages, but it's not recommended. The code for each stage will either live in a shared folder or in the API version itself. It depends how API specific the validation or serialization is. Depends on the use case. We should add a specific API validator or serializer if the use case is API format specific. We should put everything else to shared. The goal is to add as much as possible into the shared API layer to reduce the logic per API version. --- Serializers and validators can be added: - for each request - for specific controllers - for specific actions --- There is room for improvements/extensions: 1. Remove http header configuration from the API controller, because the API controller should not know about http - decouple. 2. Put permissions helpers into shared. I've just extracted and capsulated the permissions helpers into a single file for now. It had no priority. The focus was on the framework itself. etc. --- You can find more information about it in the API README.md (api/README.md) - e.g. find more information about the structure - e.g. example controllers The docs are not perfect. We will improve the docs in the next two weeks. --- Upcoming tasks: - prepare test env to test multiple API versions - copy over the controllers from v0.1 to v2 - adapt the v2 express app to use the v2 controllers
2018-10-05 01:50:45 +03:00
};
const frame = {};
return shared.pipeline.STAGES.permissions(apiUtils, apiConfig, apiImpl, frame)
.then((response) => {
response.should.eql('lol');
apiImpl.permissions.calledOnce.should.be.true();
apiUtils.permissions.handle.called.should.be.false();
});
});
it('skip stage', function () {
const apiConfig = {};
const apiImpl = {
permissions: false
};
const frame = {};
return shared.pipeline.STAGES.permissions(apiUtils, apiConfig, apiImpl, frame)
.then(() => {
apiUtils.permissions.handle.called.should.be.false();
});
});
it('default', function () {
const apiConfig = {};
const apiImpl = {
permissions: true
};
const frame = {};
return shared.pipeline.STAGES.permissions(apiUtils, apiConfig, apiImpl, frame)
.then(() => {
apiUtils.permissions.handle.calledOnce.should.be.true();
});
});
it('with permission config', function () {
const apiConfig = {
docName: 'posts'
};
const apiImpl = {
permissions: {
unsafeAttrs: ['test']
}
};
const frame = {
options: {}
};
return shared.pipeline.STAGES.permissions(apiUtils, apiConfig, apiImpl, frame)
.then(() => {
apiUtils.permissions.handle.calledOnce.should.be.true();
apiUtils.permissions.handle.calledWith(
{
docName: 'posts',
unsafeAttrs: ['test']
},
{
options: {}
}).should.be.true();
});
});
});
});
describe('pipeline', function () {
beforeEach(function () {
sinon.stub(shared.pipeline.STAGES.validation, 'input');
sinon.stub(shared.pipeline.STAGES.serialisation, 'input');
sinon.stub(shared.pipeline.STAGES.serialisation, 'output');
sinon.stub(shared.pipeline.STAGES, 'permissions');
sinon.stub(shared.pipeline.STAGES, 'query');
Added tiny framework to support multiple API versions (#9933) refs #9326, refs #9866 **ATTENTION: This is the first iteration. Bugs are expected.** Main Goals: - add support for multiple API versions. - do not touch v0.1 implementation - do not break v0.1 ## Problems with the existing v0.1 implementation 1. It tried to be generic and helpful, but it was a mixture of generic and explicit logic living in basically two files: utils.js and index.js. 2. Supporting multiple api versions means, you want to have as less as possible code per API version. With v0.1 it is impossible to reduce the API controller implementation. ---- This commit adds three things: 1. The tiny framework with well-defined API stages. 2. An example implementation of serving static pages via /pages for the content v2 API. 3. Unit tests to prove that the API framework works in general. ## API Stages - validation - input serialization - permissions - query - output serialization Each request should go through these stages. It is possible to disable stages, but it's not recommended. The code for each stage will either live in a shared folder or in the API version itself. It depends how API specific the validation or serialization is. Depends on the use case. We should add a specific API validator or serializer if the use case is API format specific. We should put everything else to shared. The goal is to add as much as possible into the shared API layer to reduce the logic per API version. --- Serializers and validators can be added: - for each request - for specific controllers - for specific actions --- There is room for improvements/extensions: 1. Remove http header configuration from the API controller, because the API controller should not know about http - decouple. 2. Put permissions helpers into shared. I've just extracted and capsulated the permissions helpers into a single file for now. It had no priority. The focus was on the framework itself. etc. --- You can find more information about it in the API README.md (api/README.md) - e.g. find more information about the structure - e.g. example controllers The docs are not perfect. We will improve the docs in the next two weeks. --- Upcoming tasks: - prepare test env to test multiple API versions - copy over the controllers from v0.1 to v2 - adapt the v2 express app to use the v2 controllers
2018-10-05 01:50:45 +03:00
});
it('ensure we receive a callable api controller fn', function () {
const apiController = {
add: {},
browse: {}
};
const apiUtils = {};
const result = shared.pipeline(apiController, apiUtils);
result.should.be.an.Object();
should.exist(result.add);
should.exist(result.browse);
result.add.should.be.a.Function();
result.browse.should.be.a.Function();
});
it('call api controller fn', function () {
const apiController = {
add: {}
};
const apiUtils = {};
const result = shared.pipeline(apiController, apiUtils);
shared.pipeline.STAGES.validation.input.resolves();
shared.pipeline.STAGES.serialisation.input.resolves();
shared.pipeline.STAGES.permissions.resolves();
shared.pipeline.STAGES.query.resolves('response');
shared.pipeline.STAGES.serialisation.output.callsFake(function (response, _apiUtils, apiConfig, apiImpl, frame) {
Added tiny framework to support multiple API versions (#9933) refs #9326, refs #9866 **ATTENTION: This is the first iteration. Bugs are expected.** Main Goals: - add support for multiple API versions. - do not touch v0.1 implementation - do not break v0.1 ## Problems with the existing v0.1 implementation 1. It tried to be generic and helpful, but it was a mixture of generic and explicit logic living in basically two files: utils.js and index.js. 2. Supporting multiple api versions means, you want to have as less as possible code per API version. With v0.1 it is impossible to reduce the API controller implementation. ---- This commit adds three things: 1. The tiny framework with well-defined API stages. 2. An example implementation of serving static pages via /pages for the content v2 API. 3. Unit tests to prove that the API framework works in general. ## API Stages - validation - input serialization - permissions - query - output serialization Each request should go through these stages. It is possible to disable stages, but it's not recommended. The code for each stage will either live in a shared folder or in the API version itself. It depends how API specific the validation or serialization is. Depends on the use case. We should add a specific API validator or serializer if the use case is API format specific. We should put everything else to shared. The goal is to add as much as possible into the shared API layer to reduce the logic per API version. --- Serializers and validators can be added: - for each request - for specific controllers - for specific actions --- There is room for improvements/extensions: 1. Remove http header configuration from the API controller, because the API controller should not know about http - decouple. 2. Put permissions helpers into shared. I've just extracted and capsulated the permissions helpers into a single file for now. It had no priority. The focus was on the framework itself. etc. --- You can find more information about it in the API README.md (api/README.md) - e.g. find more information about the structure - e.g. example controllers The docs are not perfect. We will improve the docs in the next two weeks. --- Upcoming tasks: - prepare test env to test multiple API versions - copy over the controllers from v0.1 to v2 - adapt the v2 express app to use the v2 controllers
2018-10-05 01:50:45 +03:00
frame.response = response;
});
return result.add()
.then((response) => {
response.should.eql('response');
shared.pipeline.STAGES.validation.input.calledOnce.should.be.true();
shared.pipeline.STAGES.serialisation.input.calledOnce.should.be.true();
shared.pipeline.STAGES.permissions.calledOnce.should.be.true();
shared.pipeline.STAGES.query.calledOnce.should.be.true();
shared.pipeline.STAGES.serialisation.output.calledOnce.should.be.true();
});
});
it('api controller is fn, not config', function () {
const apiController = {
add() {
return Promise.resolve('response');
}
};
const apiUtils = {};
const result = shared.pipeline(apiController, apiUtils);
return result.add()
.then((response) => {
response.should.eql('response');
shared.pipeline.STAGES.validation.input.called.should.be.false();
shared.pipeline.STAGES.serialisation.input.called.should.be.false();
shared.pipeline.STAGES.permissions.called.should.be.false();
shared.pipeline.STAGES.query.called.should.be.false();
shared.pipeline.STAGES.serialisation.output.called.should.be.false();
});
});
});
describe('caching', function () {
beforeEach(function () {
sinon.stub(shared.pipeline.STAGES.validation, 'input');
sinon.stub(shared.pipeline.STAGES.serialisation, 'input');
sinon.stub(shared.pipeline.STAGES.serialisation, 'output');
sinon.stub(shared.pipeline.STAGES, 'permissions');
sinon.stub(shared.pipeline.STAGES, 'query');
});
it('should set a cache if configured on endpoint level', async function () {
const apiController = {
browse: {
cache: {
get: sinon.stub().resolves(null),
set: sinon.stub().resolves(true)
}
}
};
const apiUtils = {};
const result = shared.pipeline(apiController, apiUtils);
shared.pipeline.STAGES.validation.input.resolves();
shared.pipeline.STAGES.serialisation.input.resolves();
shared.pipeline.STAGES.permissions.resolves();
shared.pipeline.STAGES.query.resolves('response');
shared.pipeline.STAGES.serialisation.output.callsFake(function (response, _apiUtils, apiConfig, apiImpl, frame) {
frame.response = response;
});
const response = await result.browse();
response.should.eql('response');
// request went through all stages
shared.pipeline.STAGES.validation.input.calledOnce.should.be.true();
shared.pipeline.STAGES.serialisation.input.calledOnce.should.be.true();
shared.pipeline.STAGES.permissions.calledOnce.should.be.true();
shared.pipeline.STAGES.query.calledOnce.should.be.true();
shared.pipeline.STAGES.serialisation.output.calledOnce.should.be.true();
// cache was set
apiController.browse.cache.set.calledOnce.should.be.true();
apiController.browse.cache.set.args[0][1].should.equal('response');
});
it('should use cache if configured on endpoint level', async function () {
const apiController = {
browse: {
cache: {
get: sinon.stub().resolves('CACHED RESPONSE'),
set: sinon.stub().resolves(true)
}
}
};
const apiUtils = {};
const result = shared.pipeline(apiController, apiUtils);
shared.pipeline.STAGES.validation.input.resolves();
shared.pipeline.STAGES.serialisation.input.resolves();
shared.pipeline.STAGES.permissions.resolves();
shared.pipeline.STAGES.query.resolves('response');
shared.pipeline.STAGES.serialisation.output.callsFake(function (response, _apiUtils, apiConfig, apiImpl, frame) {
frame.response = response;
});
const response = await result.browse();
response.should.eql('CACHED RESPONSE');
// request went through all stages
shared.pipeline.STAGES.validation.input.calledOnce.should.be.false();
shared.pipeline.STAGES.serialisation.input.calledOnce.should.be.false();
shared.pipeline.STAGES.permissions.calledOnce.should.be.false();
shared.pipeline.STAGES.query.calledOnce.should.be.false();
shared.pipeline.STAGES.serialisation.output.calledOnce.should.be.false();
// cache not set
apiController.browse.cache.set.calledOnce.should.be.false();
});
});
Added tiny framework to support multiple API versions (#9933) refs #9326, refs #9866 **ATTENTION: This is the first iteration. Bugs are expected.** Main Goals: - add support for multiple API versions. - do not touch v0.1 implementation - do not break v0.1 ## Problems with the existing v0.1 implementation 1. It tried to be generic and helpful, but it was a mixture of generic and explicit logic living in basically two files: utils.js and index.js. 2. Supporting multiple api versions means, you want to have as less as possible code per API version. With v0.1 it is impossible to reduce the API controller implementation. ---- This commit adds three things: 1. The tiny framework with well-defined API stages. 2. An example implementation of serving static pages via /pages for the content v2 API. 3. Unit tests to prove that the API framework works in general. ## API Stages - validation - input serialization - permissions - query - output serialization Each request should go through these stages. It is possible to disable stages, but it's not recommended. The code for each stage will either live in a shared folder or in the API version itself. It depends how API specific the validation or serialization is. Depends on the use case. We should add a specific API validator or serializer if the use case is API format specific. We should put everything else to shared. The goal is to add as much as possible into the shared API layer to reduce the logic per API version. --- Serializers and validators can be added: - for each request - for specific controllers - for specific actions --- There is room for improvements/extensions: 1. Remove http header configuration from the API controller, because the API controller should not know about http - decouple. 2. Put permissions helpers into shared. I've just extracted and capsulated the permissions helpers into a single file for now. It had no priority. The focus was on the framework itself. etc. --- You can find more information about it in the API README.md (api/README.md) - e.g. find more information about the structure - e.g. example controllers The docs are not perfect. We will improve the docs in the next two weeks. --- Upcoming tasks: - prepare test env to test multiple API versions - copy over the controllers from v0.1 to v2 - adapt the v2 express app to use the v2 controllers
2018-10-05 01:50:45 +03:00
});