Aliased canary endpoints to point to non-versioned URLs

refs https://github.com/TryGhost/Toolbox/issues/169

- Before releasing Ghost v5 we would like to move all canary-related URLs to a non-versioned format, which will become a default in v5.
- 'canary' is by definition unstable, so breaking any unprepared client explicitly using the canary is expected
- Removed the aliased /content/ and /admin/ apps from app.js because with updated configuration they become duplicates of 'canary' endpoints
This commit is contained in:
Naz 2022-03-11 19:27:43 +08:00 committed by naz
parent 40bdc3a275
commit 7becf0a2b2
16 changed files with 40 additions and 39 deletions

View File

@ -25,9 +25,6 @@ module.exports = function setupApiApp() {
apiApp.lazyUse(urlUtils.getVersionPath({version: 'canary', type: 'content'}), require('./canary/content/app'));
apiApp.lazyUse(urlUtils.getVersionPath({version: 'canary', type: 'admin'}), require('./canary/admin/app'));
apiApp.lazyUse('/content/', require('./canary/content/app'));
apiApp.lazyUse('/admin/', require('./canary/admin/app'));
// Error handling for requests to non-existent API versions
apiApp.use(errorHandler.resourceNotFound);
apiApp.use(errorHandler.handleJSONResponse(sentry));

View File

@ -79,11 +79,15 @@
},
"api": {
"versions": {
"all": ["v2", "v3", "v4", "canary"],
"all": ["v2", "v3", "v4", "v5", "canary"],
"default": "v4",
"canary": {
"admin": "canary/admin",
"content": "canary/content"
"admin": "admin",
"content": "content"
},
"v5": {
"admin": "admin",
"content": "content"
},
"v4": {
"admin": "v4/admin",

View File

@ -98,7 +98,7 @@ describe('Actions API', function () {
await integrationRequest
.put(localUtils.API.getApiQuery(`posts/${postId}/`))
.set('Origin', config.get('url'))
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/')}`)
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/admin/')}`)
.send({
posts: [{
featured: true,

View File

@ -32,7 +32,7 @@ describe('Admin API key authentication', function () {
it('Can access browse endpoint with correct token', async function () {
await request.get(localUtils.API.getApiQuery('posts/'))
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/')}`)
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/admin/')}`)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200);
@ -46,7 +46,7 @@ describe('Admin API key authentication', function () {
const res = await request
.post(localUtils.API.getApiQuery('posts/?include=authors'))
.set('Origin', config.get('url'))
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/')}`)
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/admin/')}`)
.send({
posts: [post]
})
@ -62,7 +62,7 @@ describe('Admin API key authentication', function () {
const res = await request
.get(localUtils.API.getApiQuery('users/'))
.set('Origin', config.get('url'))
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/')}`)
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/admin/')}`)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200);
@ -88,7 +88,7 @@ describe('Admin API key authentication', function () {
await testUtils.initFixtures('api_keys');
const response = await request.get(localUtils.API.getApiQuery('posts/'))
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/')}`)
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/admin/')}`)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(403);

View File

@ -129,7 +129,7 @@ describe('DB API (canary)', function () {
const fsStub = sinon.stub(fs, 'writeFile').resolves();
return request.post(localUtils.API.getApiQuery(`db/backup${backupQuery}`))
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/', backupKey)}`)
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/admin/', backupKey)}`)
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect(200)
@ -144,7 +144,7 @@ describe('DB API (canary)', function () {
const fsStub = sinon.stub(fs, 'writeFile').resolves();
return request.post(localUtils.API.getApiQuery(`db/backup`))
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/', schedulerKey)}`)
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/admin/', schedulerKey)}`)
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect(403)

View File

@ -89,7 +89,7 @@ describe('Canary Schedules API', function () {
before(function () {
const schedulerKey = _.find(testUtils.getExistingData().apiKeys, {integration: {slug: 'ghost-scheduler'}});
token = localUtils.getValidAdminToken('/canary/admin/', schedulerKey);
token = localUtils.getValidAdminToken('/admin/', schedulerKey);
});
it('publishes posts', async function () {
@ -123,7 +123,7 @@ describe('Canary Schedules API', function () {
it('no access', function () {
const zapierKey = _.find(testUtils.getExistingData().apiKeys, {integration: {slug: 'ghost-backup'}});
const zapierToken = localUtils.getValidAdminToken('/canary/admin/', zapierKey);
const zapierToken = localUtils.getValidAdminToken('/admin/', zapierKey);
return request
.put(localUtils.API.getApiQuery(`schedules/posts/${resources[0].id}/?token=${zapierToken}`))

View File

@ -1,7 +1,7 @@
const url = require('url');
const testUtils = require('../../../utils');
const API_URL = '/ghost/api/canary/admin/';
const API_URL = '/ghost/api/admin/';
const expectedProperties = {
posts: ['posts', 'meta'],

View File

@ -27,7 +27,7 @@ describe('Webhooks API (canary)', function () {
};
return request.post(localUtils.API.getApiQuery('webhooks/'))
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/', testUtils.DataGenerator.Content.api_keys[0])}`)
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/admin/', testUtils.DataGenerator.Content.api_keys[0])}`)
.send({webhooks: [webhookData]})
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
@ -134,7 +134,7 @@ describe('Webhooks API (canary)', function () {
[createdWebhook] = body.webhooks;
return request.put(localUtils.API.getApiQuery(`webhooks/${createdWebhook.id}/`))
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/', testUtils.DataGenerator.Content.api_keys[0])}`)
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/admin/', testUtils.DataGenerator.Content.api_keys[0])}`)
.send({
webhooks: [{
name: 'Edit Test',
@ -146,14 +146,14 @@ describe('Webhooks API (canary)', function () {
})
.then(() => {
return request.del(localUtils.API.getApiQuery(`webhooks/${createdWebhook.id}/`))
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/', testUtils.DataGenerator.Content.api_keys[0])}`)
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/admin/', testUtils.DataGenerator.Content.api_keys[0])}`)
.expect(403);
});
});
it('Integration editing non-existing webhook returns 404', function () {
return request.put(localUtils.API.getApiQuery(`webhooks/5f27d0287c75da744d8615da/`))
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/', testUtils.DataGenerator.Content.api_keys[0])}`)
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/admin/', testUtils.DataGenerator.Content.api_keys[0])}`)
.send({
webhooks: [{
name: 'Edit Test'
@ -164,7 +164,7 @@ describe('Webhooks API (canary)', function () {
it('Integration deleting non-existing webhook returns 404', function () {
return request.delete(localUtils.API.getApiQuery(`webhooks/5f27d0287c75da744d8615db/`))
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/', testUtils.DataGenerator.Content.api_keys[0])}`)
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/admin/', testUtils.DataGenerator.Content.api_keys[0])}`)
.expect(404);
});
@ -175,7 +175,7 @@ describe('Webhooks API (canary)', function () {
};
return request.post(localUtils.API.getApiQuery('webhooks/'))
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/', testUtils.DataGenerator.Content.api_keys[1])}`)
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/admin/', testUtils.DataGenerator.Content.api_keys[1])}`)
.send({webhooks: [webhookData]})
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)

View File

@ -220,7 +220,7 @@ describe('api/canary/content/posts', function () {
}
res.headers.vary.should.eql('Accept, Accept-Encoding');
res.headers.location.should.eql(`http://localhost:9999/ghost/api/canary/content/posts/?key=${validKey}`);
res.headers.location.should.eql(`http://localhost:9999/ghost/api/content/posts/?key=${validKey}`);
should.exist(res.headers['access-control-allow-origin']);
should.not.exist(res.headers['x-cache-invalidate']);
done();

View File

@ -2,7 +2,7 @@ const url = require('url');
const _ = require('lodash');
const testUtils = require('../../../utils');
const schema = require('../../../../core/server/data/schema').tables;
const API_URL = '/ghost/api/canary/content/';
const API_URL = '/ghost/api/content/';
const expectedProperties = {
// API top level

View File

@ -9,7 +9,7 @@ const themeEngine = require('../../../core/frontend/services/theme-engine');
describe('Integration - Web - vhosts', function () {
let app;
const ADMIN_API_URL = '/ghost/api/canary/admin';
const ADMIN_API_URL = '/ghost/api/admin';
before(testUtils.teardownDb);

View File

@ -56,7 +56,7 @@ describe('Themes: engines', function () {
it('not supported upcoming version falls back to default version', function () {
const engines = themeEngines.create({
engines: {
'ghost-api': 'v5'
'ghost-api': 'v6'
}
});

View File

@ -6,7 +6,7 @@ const apiKeyAuth = require('../../../../../../core/server/services/auth/api-key'
const models = require('../../../../../../core/server/models');
describe('Admin API Key Auth', function () {
const ADMIN_API_URL = '/ghost/api/canary/admin/';
const ADMIN_API_URL = '/ghost/api/v4/admin/';
const ADMIN_API_URL_NON_VERSIONED = '/ghost/api/admin/';
before(models.init);
@ -32,13 +32,13 @@ describe('Admin API Key Auth', function () {
sinon.restore();
});
it('should authenticate known+valid canary API key', function (done) {
it('should authenticate known+valid v4 API key', function (done) {
const token = jwt.sign({
}, this.secret, {
keyid: this.fakeApiKey.id,
algorithm: 'HS256',
expiresIn: '5m',
audience: '/canary/admin/',
audience: '/v4/admin/',
issuer: this.fakeApiKey.id
});
@ -153,7 +153,7 @@ describe('Admin API Key Auth', function () {
keyid: this.fakeApiKey.id,
algorithm: 'HS256',
expiresIn: '5m',
audience: '/canary/admin/',
audience: '/v4/admin/',
issuer: this.fakeApiKey.id
});
@ -183,7 +183,7 @@ describe('Admin API Key Auth', function () {
keyid: this.fakeApiKey.id,
algorithm: 'HS256',
expiresIn: '10m',
audience: '/canary/admin/',
audience: '/v4/admin/',
issuer: this.fakeApiKey.id
});
@ -211,7 +211,7 @@ describe('Admin API Key Auth', function () {
keyid: this.fakeApiKey.id,
algorithm: 'HS256',
expiresIn: '5m',
audience: '/canary/admin/',
audience: 'v4/admin/',
issuer: this.fakeApiKey.id
});

View File

@ -49,8 +49,8 @@ function createUrlUtilsMock() {
apiVersions: {
all: ['canary'],
canary: {
admin: 'canary/admin',
content: 'canary/content'
admin: 'admin',
content: 'content'
}
},
defaultApiVersion: 'canary',

View File

@ -50,8 +50,8 @@ function createUrlUtilsMock() {
apiVersions: {
all: ['canary'],
canary: {
admin: 'canary/admin',
content: 'canary/content'
admin: 'admin',
content: 'content'
}
},
defaultApiVersion: 'canary',

View File

@ -155,7 +155,7 @@ const getContentAPIAgent = async () => {
const originURL = configUtils.config.get('url');
return new ContentAPITestAgent(app, {
apiURL: '/ghost/api/canary/content/',
apiURL: '/ghost/api/content/',
originURL
});
} catch (error) {
@ -185,7 +185,7 @@ const getAdminAPIAgent = async (options = {}) => {
const originURL = configUtils.config.get('url');
return new AdminAPITestAgent(app, {
apiURL: '/ghost/api/canary/admin/',
apiURL: '/ghost/api/admin/',
originURL
});
} catch (error) {
@ -240,7 +240,7 @@ const getAgentsForMembers = async () => {
originURL
});
adminAgent = new AdminAPITestAgent(app, {
apiURL: '/ghost/api/canary/admin/',
apiURL: '/ghost/api/admin/',
originURL
});
} catch (error) {