Supported setting headers on a per-request basis

refs https://linear.app/tryghost/issue/ENG-674

This paves the way for us to have dynamic cache invalidation headers
without clobbering the shared headers config.
This commit is contained in:
Fabien O'Carroll 2024-02-27 16:13:08 -05:00 committed by Fabien 'egg' O'Carroll
parent b91bf74236
commit a177600b30
3 changed files with 61 additions and 50 deletions

View File

@ -9,6 +9,7 @@ const _ = require('lodash');
* easiest to use. We always have access to the original input, we never loose track of it.
*/
class Frame {
#headers = {};
constructor(obj = {}) {
this.original = obj;
@ -27,6 +28,7 @@ class Frame {
this.user = {};
this.file = {};
this.files = [];
this.#headers = {};
this.apiType = null;
this.docName = null;
this.method = null;
@ -95,6 +97,14 @@ class Frame {
debug('options', this.options);
debug('data', this.data);
}
setHeader(header, value) {
this.#headers[header] = value;
}
getHeaders() {
return Object.assign({}, this.#headers);
}
}
module.exports = Frame;

View File

@ -147,6 +147,10 @@ module.exports = {
Object.assign(headers, locationHeader);
}
const headersFromFrame = frame.getHeaders();
Object.assign(headers, headersFromFrame);
debug(headers);
return headers;
}

View File

@ -1,15 +1,16 @@
const shared = require('../');
const Frame = require('../lib/Frame');
describe('Headers', function () {
it('empty headers config', function () {
return shared.headers.get().then((result) => {
return shared.headers.get({}, {}, new Frame()).then((result) => {
result.should.eql({});
});
});
describe('config.disposition', function () {
it('json', function () {
return shared.headers.get({}, {disposition: {type: 'json', value: 'value'}})
return shared.headers.get({}, {disposition: {type: 'json', value: 'value'}}, new Frame())
.then((result) => {
result.should.eql({
'Content-Disposition': 'Attachment; filename="value"',
@ -20,7 +21,7 @@ describe('Headers', function () {
});
it('csv', function () {
return shared.headers.get({}, {disposition: {type: 'csv', value: 'my.csv'}})
return shared.headers.get({}, {disposition: {type: 'csv', value: 'my.csv'}}, new Frame())
.then((result) => {
result.should.eql({
'Content-Disposition': 'Attachment; filename="my.csv"',
@ -39,7 +40,7 @@ describe('Headers', function () {
return filename;
}
}
});
}, new Frame());
result.should.eql({
'Content-Disposition': 'Attachment; filename="awesome-data-2022-08-01.csv"',
'Content-Type': 'text/csv'
@ -47,7 +48,7 @@ describe('Headers', function () {
});
it('file', async function () {
const result = await shared.headers.get({}, {disposition: {type: 'file', value: 'my.txt'}});
const result = await shared.headers.get({}, {disposition: {type: 'file', value: 'my.txt'}}, new Frame());
result.should.eql({
'Content-Disposition': 'Attachment; filename="my.txt"'
});
@ -63,14 +64,14 @@ describe('Headers', function () {
return filename;
}
}
});
}, new Frame());
result.should.eql({
'Content-Disposition': 'Attachment; filename="awesome-data-2022-08-01.txt"'
});
});
it('yaml', function () {
return shared.headers.get('yaml file', {disposition: {type: 'yaml', value: 'my.yaml'}})
return shared.headers.get('yaml file', {disposition: {type: 'yaml', value: 'my.yaml'}}, new Frame())
.then((result) => {
result.should.eql({
'Content-Disposition': 'Attachment; filename="my.yaml"',
@ -83,7 +84,7 @@ describe('Headers', function () {
describe('config.cacheInvalidate', function () {
it('default', function () {
return shared.headers.get({}, {cacheInvalidate: true})
return shared.headers.get({}, {cacheInvalidate: true}, new Frame())
.then((result) => {
result.should.eql({
'X-Cache-Invalidate': '/*'
@ -92,7 +93,7 @@ describe('Headers', function () {
});
it('custom value', function () {
return shared.headers.get({}, {cacheInvalidate: {value: 'value'}})
return shared.headers.get({}, {cacheInvalidate: {value: 'value'}}, new Frame())
.then((result) => {
result.should.eql({
'X-Cache-Invalidate': 'value'
@ -110,15 +111,14 @@ describe('Headers', function () {
};
const apiConfigHeaders = {};
const frame = {
docName: 'posts',
method: 'add',
original: {
const frame = new Frame();
frame.docName = 'posts',
frame.method = 'add',
frame.original = {
url: {
host: 'example.com',
pathname: `/api/content/posts/`
}
}
};
return shared.headers.get(apiResult, apiConfigHeaders, frame)
@ -146,15 +146,14 @@ describe('Headers', function () {
}
}
};
const frame = {
docName: 'posts',
method: 'copy',
original: {
const frame = new Frame();
frame.docName = 'posts';
frame.method = 'copy';
frame.original = {
url: {
host: 'example.com',
pathname: `/api/content/posts/existing_post_id_value/copy`
}
}
};
return shared.headers.get(apiResult, apiConfigHeaders, frame)
@ -173,16 +172,16 @@ describe('Headers', function () {
};
const apiConfigHeaders = {};
const frame = {
docName: 'posts',
method: 'add',
original: {
const frame = new Frame();
frame.docName = 'posts';
frame.method = 'add';
frame.original = {
url: {
host: 'example.com',
pathname: `/api/content/posts/`,
secure: false
}
}
};
const result = await shared.headers.get(apiResult, apiConfigHeaders, frame);
@ -200,15 +199,14 @@ describe('Headers', function () {
};
const apiConfigHeaders = {};
const frame = {
docName: 'posts',
method: 'add',
original: {
const frame = new Frame();
frame.docName = 'posts';
frame.method = 'add';
frame.original = {
url: {
host: 'example.com',
pathname: `/api/content/posts`
}
}
};
return shared.headers.get(apiResult, apiConfigHeaders, frame)
@ -224,15 +222,14 @@ describe('Headers', function () {
const apiResult = {};
const apiConfigHeaders = {};
const frame = {
docName: 'posts',
method: 'add',
original: {
const frame = new Frame();
frame.docName = 'posts';
frame.method = 'add';
frame.original = {
url: {
host: 'example.com',
pathname: `/api/content/posts/`
}
}
};
return shared.headers.get(apiResult, apiConfigHeaders, frame)