mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-11 02:12:21 -05:00
Added 'content-version' header response
refs https://github.com/TryGhost/Toolbox/issues/280 - In response to 'Accept-Version' header in the request headers, Ghost will always respond with a content-version header indicating the version of the Ghost install that is responding. This should signal to the client the content version that is bein g served - This is a bare bones implementation and more logic with edge cases where `content-version` is served with a version value of "best format API could respond with" will be added later.
This commit is contained in:
parent
132726fe20
commit
76aa2479f8
4 changed files with 84 additions and 2 deletions
|
@ -64,7 +64,7 @@ const http = (apiImpl) => {
|
||||||
const result = await apiImpl(frame);
|
const result = await apiImpl(frame);
|
||||||
|
|
||||||
debug(`External API request to ${frame.docName}.${frame.method}`);
|
debug(`External API request to ${frame.docName}.${frame.method}`);
|
||||||
const headers = await shared.headers.get(result, apiImpl.headers, frame);
|
const headers = await shared.headers.get(result, apiImpl.headers, frame) || {};
|
||||||
|
|
||||||
// CASE: api ctrl wants to handle the express response (e.g. streams)
|
// CASE: api ctrl wants to handle the express response (e.g. streams)
|
||||||
if (typeof result === 'function') {
|
if (typeof result === 'function') {
|
||||||
|
@ -82,6 +82,9 @@ const http = (apiImpl) => {
|
||||||
res.status(statusCode);
|
res.status(statusCode);
|
||||||
|
|
||||||
// CASE: generate headers based on the api ctrl configuration
|
// CASE: generate headers based on the api ctrl configuration
|
||||||
|
if (req && req.headers && req.headers['accept-version'] && res.locals) {
|
||||||
|
headers['content-version'] = `v${res.locals.safeVersion}`;
|
||||||
|
}
|
||||||
res.set(headers);
|
res.set(headers);
|
||||||
|
|
||||||
const send = (format) => {
|
const send = (format) => {
|
||||||
|
|
26
test/e2e-api/admin/__snapshots__/version.test.js.snap
Normal file
26
test/e2e-api/admin/__snapshots__/version.test.js.snap
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`API Versioning responds with current content version header when requested version is behind current version with no known changes 1: [headers] 1`] = `
|
||||||
|
Object {
|
||||||
|
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||||
|
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||||
|
"content-length": "167",
|
||||||
|
"content-type": "application/json; charset=utf-8",
|
||||||
|
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||||
|
"etag": Any<String>,
|
||||||
|
"vary": "Origin, Accept-Encoding",
|
||||||
|
"x-powered-by": "Express",
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`API Versioning responds with no content version header when accept version header is not present 1: [headers] 1`] = `
|
||||||
|
Object {
|
||||||
|
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||||
|
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||||
|
"content-length": "167",
|
||||||
|
"content-type": "application/json; charset=utf-8",
|
||||||
|
"etag": Any<String>,
|
||||||
|
"vary": "Origin, Accept-Encoding",
|
||||||
|
"x-powered-by": "Express",
|
||||||
|
}
|
||||||
|
`;
|
28
test/e2e-api/admin/version.test.js
Normal file
28
test/e2e-api/admin/version.test.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
const {agentProvider, matchers} = require('../../utils/e2e-framework');
|
||||||
|
const {anyString, stringMatching} = matchers;
|
||||||
|
|
||||||
|
describe('API Versioning', function () {
|
||||||
|
let agent;
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
agent = await agentProvider.getAdminAPIAgent();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('responds with no content version header when accept version header is NOT PRESENT', async function () {
|
||||||
|
await agent
|
||||||
|
.get('site/')
|
||||||
|
.matchHeaderSnapshot({
|
||||||
|
etag: anyString
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('responds with current content version header when requested version is behind current version with no known changes', async function () {
|
||||||
|
await agent
|
||||||
|
.get('site/')
|
||||||
|
.header('Accept-Version', 'v3.0')
|
||||||
|
.matchHeaderSnapshot({
|
||||||
|
etag: anyString,
|
||||||
|
'content-version': stringMatching(/v\d+\.\d+/)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -22,7 +22,9 @@ describe('Unit: api/shared/http', function () {
|
||||||
|
|
||||||
res.status = sinon.stub();
|
res.status = sinon.stub();
|
||||||
res.json = sinon.stub();
|
res.json = sinon.stub();
|
||||||
res.set = sinon.stub();
|
res.set = (headers) => {
|
||||||
|
res.headers = headers;
|
||||||
|
};
|
||||||
res.send = sinon.stub();
|
res.send = sinon.stub();
|
||||||
|
|
||||||
sinon.stub(shared.headers, 'get').resolves();
|
sinon.stub(shared.headers, 'get').resolves();
|
||||||
|
@ -85,4 +87,27 @@ describe('Unit: api/shared/http', function () {
|
||||||
|
|
||||||
shared.http(apiImpl)(req, res, next);
|
shared.http(apiImpl)(req, res, next);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('adds content-version header to the response when accept-version header is present in the request', function (done) {
|
||||||
|
const apiImpl = sinon.stub().resolves('data');
|
||||||
|
req.headers = {
|
||||||
|
'accept-version': 'v5.1'
|
||||||
|
};
|
||||||
|
apiImpl.headers = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
};
|
||||||
|
res.locals = {
|
||||||
|
safeVersion: '5.4'
|
||||||
|
};
|
||||||
|
next.callsFake(done);
|
||||||
|
|
||||||
|
res.json.callsFake(function () {
|
||||||
|
shared.headers.get.calledOnce.should.be.true();
|
||||||
|
res.status.calledOnce.should.be.true();
|
||||||
|
res.headers['content-version'].should.equal('v5.4');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
shared.http(apiImpl)(req, res, next);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue