Fixed api-version-compatibility-service init error

closes: https://github.com/TryGhost/Toolbox/issues/317

- Added two tests for unknown versions with accept-versions set ahead and behind
   - Ahead passes, but we get an error for behind
- Refactored the api-version-compatibility-service to expose its own middleware so the init sequence is correct
This commit is contained in:
Hannah Wolfe 2022-05-02 16:00:15 +01:00
parent 03c8e7f010
commit 55ce208ebb
5 changed files with 95 additions and 8 deletions

View File

@ -1,10 +1,13 @@
const APIVersionCompatibilityService = require('@tryghost/api-version-compatibility-service');
const VersionNotificationsDataService = require('@tryghost/version-notifications-data-service');
const versionMismatchHandler = require('@tryghost/mw-api-version-mismatch');
// const {GhostMailer} = require('../mail');
const settingsService = require('../../services/settings');
const models = require('../../models');
const logging = require('@tryghost/logging');
let serviceInstance;
const init = () => {
//const ghostMailer = new GhostMailer();
const versionNotificationsDataService = new VersionNotificationsDataService({
@ -12,7 +15,7 @@ const init = () => {
settingsService: settingsService.getSettingsBREADServiceInstance()
});
this.APIVersionCompatibilityServiceInstance = new APIVersionCompatibilityService({
serviceInstance = new APIVersionCompatibilityService({
sendEmail: (options) => {
// NOTE: not using bind here because mockMailer is having trouble mocking bound methods
//return ghostMailer.send(options);
@ -25,5 +28,7 @@ const init = () => {
});
};
module.exports.APIVersionCompatibilityServiceInstance;
module.exports.errorHandler = (req, res, next) => {
return versionMismatchHandler(serviceInstance)(req, res, next);
};
module.exports.init = init;

View File

@ -3,8 +3,7 @@ const config = require('../../../shared/config');
const express = require('../../../shared/express');
const sentry = require('../../../shared/sentry');
const errorHandler = require('@tryghost/mw-error-handler');
const versionMissmatchHandler = require('@tryghost/mw-api-version-mismatch');
const {APIVersionCompatibilityServiceInstance} = require('../../services/api-version-compatibility');
const APIVersionCompatibilityService = require('../../services/api-version-compatibility');
module.exports = function setupApiApp() {
debug('Parent API setup start');
@ -32,7 +31,7 @@ module.exports = function setupApiApp() {
// Error handling for requests to non-existent API versions
apiApp.use(errorHandler.resourceNotFound);
apiApp.use(versionMissmatchHandler(APIVersionCompatibilityServiceInstance));
apiApp.use(APIVersionCompatibilityService.errorHandler);
apiApp.use(errorHandler.handleJSONResponseV2(sentry));
debug('Parent API setup end');

View File

@ -5,10 +5,9 @@ const bodyParser = require('body-parser');
const shared = require('../../../shared');
const apiMw = require('../../middleware');
const errorHandler = require('@tryghost/mw-error-handler');
const versionMissmatchHandler = require('@tryghost/mw-api-version-mismatch');
const sentry = require('../../../../../shared/sentry');
const routes = require('./routes');
const {APIVersionCompatibilityServiceInstance} = require('../../../../services/api-version-compatibility');
const APIVersionCompatibilityService = require('../../../../services/api-version-compatibility');
module.exports = function setupApiApp() {
debug('Admin API canary setup start');
@ -35,7 +34,7 @@ module.exports = function setupApiApp() {
// API error handling
apiApp.use(errorHandler.resourceNotFound);
apiApp.use(versionMissmatchHandler(APIVersionCompatibilityServiceInstance));
apiApp.use(APIVersionCompatibilityService.errorHandler);
apiApp.use(errorHandler.handleJSONResponseV2(sentry));
debug('Admin API canary setup end');

View File

@ -62,6 +62,62 @@ Object {
}
`;
exports[`API Versioning Admin API responds with 406 for an unknown version with accept-version set ahead 1: [body] 1`] = `
Object {
"errors": Array [
Object {
"code": "UPDATE_GHOST",
"context": StringMatching /Provided client version v99\\\\\\.0 is ahead of current Ghost instance version v\\\\d\\+\\\\\\.\\\\d\\+/,
"details": null,
"help": "Upgrade your Ghost instance.",
"id": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"message": "Request not acceptable for provided Accept-Version header.",
"property": null,
"type": "RequestNotAcceptableError",
},
],
}
`;
exports[`API Versioning Admin API responds with 406 for an unknown version with accept-version set ahead 2: [headers] 1`] = `
Object {
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "347",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Encoding",
"x-powered-by": "Express",
}
`;
exports[`API Versioning Admin API responds with 406 for an unknown version with accept-version set behind 1: [body] 1`] = `
Object {
"errors": Array [
Object {
"code": "UPDATE_CLIENT",
"context": StringMatching /Provided client version v1\\\\\\.0 is outdated and is behind current Ghost version v\\\\d\\+\\\\\\.\\\\d\\+/,
"details": null,
"help": "Upgrade your Ghost API client.",
"id": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"message": "Request not acceptable for provided Accept-Version header.",
"property": null,
"type": "RequestNotAcceptableError",
},
],
}
`;
exports[`API Versioning Admin API responds with 406 for an unknown version with accept-version set behind 2: [headers] 1`] = `
Object {
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "354",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Encoding",
"x-powered-by": "Express",
}
`;
exports[`API Versioning Admin API responds with current content version header when requested version is AHEAD and CAN respond 1: [body] 1`] = `
Object {
"site": Object {

View File

@ -183,6 +183,34 @@ describe('API Versioning', function () {
})
.expectEmptyBody();
});
it('responds with 406 for an unknown version with accept-version set ahead', async function () {
await agentAdminAPI
.get('/site/', {baseUrl: '/ghost/api/v99/admin/'})
.header('Accept-Version', 'v99.0')
.expectStatus(406)
.matchHeaderSnapshot({
etag: anyEtag
})
.matchBodySnapshot({errors: [{
context: stringMatching(/Provided client version v99\.0 is ahead of current Ghost instance version v\d+\.\d+/),
id: anyErrorId
}]});
});
it('responds with 406 for an unknown version with accept-version set behind', async function () {
await agentAdminAPI
.get('/site/', {baseUrl: '/ghost/api/v1/admin/'})
.header('Accept-Version', 'v1.0')
.expectStatus(406)
.matchHeaderSnapshot({
etag: anyEtag
})
.matchBodySnapshot({errors: [{
context: stringMatching(/Provided client version v1\.0 is outdated and is behind current Ghost version v\d+\.\d+/),
id: anyErrorId
}]});
});
});
describe('Content API', function () {