mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-04-15 03:01:37 -05:00
Added 307 redirects for old API endpoints
closes: https://github.com/TryGhost/Toolbox/issues/296 - This is a small change to permit any known API version to redirect to an unversioned URL - We include v2 because although it should have been deleted in 5.0 anyway, in the spirit of the change away from versioned URLs there's absolutely no sense in forcing people to update clients that still work for no reason. - We use a 307, because this preserves the original HTTP method, allowing POSTS, PUTs and DELETEs through as well as GETs - We set the accept-version header on the redirect, meaning that for example with a request to the old /v4/ api, Ghost will respond as though the client sent `accept-version: v4.0` and if there are known breaking changes, it may choose to inform the admin and owner users of these
This commit is contained in:
parent
5e020f1a8f
commit
0eedb1c556
3 changed files with 88 additions and 1 deletions
|
@ -14,6 +14,19 @@ module.exports = function setupApiApp() {
|
|||
apiApp.use(require('./testmode')());
|
||||
}
|
||||
|
||||
// If there is a version in the URL, and this is a valid API URL containing admin/content
|
||||
// Then 307 redirect (preserves the HTTP method) to a versionless URL with `accept-version` set.
|
||||
apiApp.all('/:version(v2|v3|v4|canary)/:api(admin|content)/*', (req, res) => {
|
||||
const {version} = req.params;
|
||||
const versionlessURL = req.originalUrl.replace(`${version}/`, '');
|
||||
if (version.startsWith('v')) {
|
||||
res.header('accept-version', `${version}.0`);
|
||||
} else {
|
||||
res.header('accept-version', version);
|
||||
}
|
||||
res.redirect(307, versionlessURL);
|
||||
});
|
||||
|
||||
apiApp.lazyUse('/content/', require('./canary/content/app'));
|
||||
apiApp.lazyUse('/admin/', require('./canary/admin/app'));
|
||||
|
||||
|
|
|
@ -1,5 +1,38 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`API Versioning Admin API 307 redirects GET with accept version set when version is included in the URL 1: [headers] 1`] = `
|
||||
Object {
|
||||
"accept-version": "canary",
|
||||
"content-length": "57",
|
||||
"content-type": "text/plain; charset=utf-8",
|
||||
"location": StringMatching /\\^\\\\/ghost\\\\/api\\\\/admin\\\\/site\\\\/\\$/,
|
||||
"vary": "Accept, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`API Versioning Admin API 307 redirects POST with accept version set when version is included in the URL 1: [headers] 1`] = `
|
||||
Object {
|
||||
"accept-version": "v3.0",
|
||||
"content-length": "60",
|
||||
"content-type": "text/plain; charset=utf-8",
|
||||
"location": StringMatching /\\^\\\\/ghost\\\\/api\\\\/admin\\\\/session\\\\/\\$/,
|
||||
"vary": "Accept, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`API Versioning Admin API 307 redirects with accept version set when version is included in the URL 1: [headers] 1`] = `
|
||||
Object {
|
||||
"accept-version": "canary",
|
||||
"content-length": "57",
|
||||
"content-type": "text/plain; charset=utf-8",
|
||||
"location": StringMatching /\\^\\\\/ghost\\\\/api\\\\/admin\\\\/site\\\\/\\$/,
|
||||
"vary": "Accept, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`API Versioning Admin API responds with 404 error when the resource cannot be found 1: [body] 1`] = `
|
||||
Object {
|
||||
"errors": Array [
|
||||
|
@ -225,6 +258,17 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`API Versioning Content API 307 redirects with accept version set when version is included in the URL 1: [headers] 1`] = `
|
||||
Object {
|
||||
"accept-version": "canary",
|
||||
"content-length": "91",
|
||||
"content-type": "text/plain; charset=utf-8",
|
||||
"location": StringMatching /\\^\\\\/ghost\\\\/api\\\\/content\\\\/posts\\\\//,
|
||||
"vary": "Accept, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`API Versioning Content API responds with current content version header when requested version is BEHIND current version and CAN respond 1: [body] 1`] = `
|
||||
Object {
|
||||
"meta": Object {},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const {agentProvider, fixtureManager, matchers, mockManager} = require('../../utils/e2e-framework');
|
||||
const {anyErrorId, anyString, stringMatching} = matchers;
|
||||
const {anyErrorId, anyString, stringMatching, anyLocationFor} = matchers;
|
||||
|
||||
describe('API Versioning', function () {
|
||||
describe('Admin API', function () {
|
||||
|
@ -163,6 +163,26 @@ describe('API Versioning', function () {
|
|||
}]
|
||||
});
|
||||
});
|
||||
|
||||
it('307 redirects GET with accept version set when version is included in the URL', async function () {
|
||||
await agentAdminAPI
|
||||
.get('/site/', {baseUrl: '/ghost/api/canary/admin/'})
|
||||
.expectStatus(307)
|
||||
.matchHeaderSnapshot({
|
||||
location: stringMatching(/^\/ghost\/api\/admin\/site\/$/)
|
||||
})
|
||||
.expectEmptyBody();
|
||||
});
|
||||
|
||||
it('307 redirects POST with accept version set when version is included in the URL', async function () {
|
||||
await agentAdminAPI
|
||||
.post('/session/', {baseUrl: '/ghost/api/v3/admin/'})
|
||||
.expectStatus(307)
|
||||
.matchHeaderSnapshot({
|
||||
location: stringMatching(/^\/ghost\/api\/admin\/session\/$/)
|
||||
})
|
||||
.expectEmptyBody();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Content API', function () {
|
||||
|
@ -190,5 +210,15 @@ describe('API Versioning', function () {
|
|||
})
|
||||
.matchBodySnapshot();
|
||||
});
|
||||
|
||||
it('307 redirects with accept version set when version is included in the URL', async function () {
|
||||
await agentContentAPI
|
||||
.get('/posts/', {baseUrl: '/ghost/api/canary/content/'})
|
||||
.expectStatus(307)
|
||||
.matchHeaderSnapshot({
|
||||
location: stringMatching(/^\/ghost\/api\/content\/posts\//)
|
||||
})
|
||||
.expectEmptyBody();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue