Prevented pages content api queries from returning mobiledoc or lexical fields (#20454)
ref https://linear.app/tryghost/issue/CFR-43/
ref 9d9a421
We recently stopped `select *` from posts when making Content API
requests. This is now being applied to the pages endpoint to help
improve performance. These fields were already being stripped out in the
output serializer, and they will now no longer be returned from the db
at all, reducing the amount of data transferred.
This commit is contained in:
parent
b9240271fe
commit
b10b81b7d7
@ -7,6 +7,7 @@ const slugFilterOrder = require('./utils/slug-filter-order');
|
||||
const localUtils = require('../../index');
|
||||
const mobiledoc = require('../../../../../lib/mobiledoc');
|
||||
const postsMetaSchema = require('../../../../../data/schema').tables.posts_meta;
|
||||
const postsSchema = require('../../../../../data/schema').tables.posts;
|
||||
const clean = require('./utils/clean');
|
||||
const lexical = require('../../../../../lib/lexical');
|
||||
const sentry = require('../../../../../../shared/sentry');
|
||||
@ -24,6 +25,33 @@ function removeSourceFormats(frame) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects all allowed columns for the given frame.
|
||||
*
|
||||
* This removes the lexical and mobiledoc columns from the query. This is a performance improvement as we never intend
|
||||
* to expose those columns in the content API and they are very large datasets to be passing around and de/serializing.
|
||||
*
|
||||
* NOTE: This is only intended for the Content API. We need these fields within Admin API responses.
|
||||
*
|
||||
* @param {Object} frame - The frame object.
|
||||
*/
|
||||
function selectAllAllowedColumns(frame) {
|
||||
if (!frame.options.columns && !frame.options.selectRaw) {
|
||||
// Because we're returning columns directly from the schema we need to remove info columns like @@UNIQUE_CONSTRAINTS@@ and @@INDEXES@@
|
||||
frame.options.selectRaw = _.keys(_.omit(postsSchema, ['lexical','mobiledoc','@@INDEXES@@','@@UNIQUE_CONSTRAINTS@@'])).join(',');
|
||||
} else if (frame.options.columns) {
|
||||
frame.options.columns = frame.options.columns.filter((column) => {
|
||||
return !['mobiledoc', 'lexical'].includes(column);
|
||||
});
|
||||
} else if (frame.options.selectRaw) {
|
||||
frame.options.selectRaw = frame.options.selectRaw.split(',').map((column) => {
|
||||
return column.trim();
|
||||
}).filter((column) => {
|
||||
return !['mobiledoc', 'lexical'].includes(column);
|
||||
}).join(',');
|
||||
}
|
||||
}
|
||||
|
||||
function defaultRelations(frame) {
|
||||
if (frame.options.withRelated) {
|
||||
return;
|
||||
@ -97,7 +125,10 @@ module.exports = {
|
||||
forcePageFilter(frame);
|
||||
|
||||
if (localUtils.isContentAPI(frame)) {
|
||||
removeSourceFormats(frame);
|
||||
// CASE: the content api endpoint for posts should not return mobiledoc or lexical
|
||||
removeSourceFormats(frame); // remove from the format field
|
||||
selectAllAllowedColumns(frame); // remove from any specified column or selectRaw options
|
||||
|
||||
setDefaultOrder(frame);
|
||||
forceVisibilityColumn(frame);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
const should = require('should');
|
||||
const sinon = require('sinon');
|
||||
const serializers = require('../../../../../../../core/server/api/endpoints/utils/serializers');
|
||||
const postsSchema = require('../../../../../../../core/server/data/schema').tables.posts;
|
||||
|
||||
const mobiledocLib = require('@tryghost/html-to-mobiledoc');
|
||||
|
||||
@ -67,6 +68,65 @@ describe('Unit: endpoints/utils/serializers/input/pages', function () {
|
||||
frame.options.formats.should.containEql('html');
|
||||
frame.options.formats.should.containEql('plaintext');
|
||||
});
|
||||
|
||||
describe('Content API', function () {
|
||||
it('selects all columns from the posts schema but mobiledoc and lexical when no columns are specified', function () {
|
||||
const apiConfig = {};
|
||||
const frame = {
|
||||
apiType: 'content',
|
||||
options: {
|
||||
context: {}
|
||||
}
|
||||
};
|
||||
|
||||
serializers.input.pages.browse(apiConfig, frame);
|
||||
const columns = Object.keys(postsSchema);
|
||||
const parsedSelectRaw = frame.options.selectRaw.split(',').map(column => column.trim());
|
||||
parsedSelectRaw.should.eql(columns.filter(column => !['mobiledoc', 'lexical','@@UNIQUE_CONSTRAINTS@@','@@INDEXES@@'].includes(column)));
|
||||
});
|
||||
|
||||
it('strips mobiledoc and lexical columns from a specified columns option', function () {
|
||||
const apiConfig = {};
|
||||
const frame = {
|
||||
apiType: 'content',
|
||||
options: {
|
||||
context: {},
|
||||
columns: ['id', 'mobiledoc', 'lexical', 'visibility']
|
||||
}
|
||||
};
|
||||
|
||||
serializers.input.pages.browse(apiConfig, frame);
|
||||
frame.options.columns.should.eql(['id', 'visibility']);
|
||||
});
|
||||
|
||||
it('forces visibility column if columns are specified', function () {
|
||||
const apiConfig = {};
|
||||
const frame = {
|
||||
apiType: 'content',
|
||||
options: {
|
||||
context: {},
|
||||
columns: ['id']
|
||||
}
|
||||
};
|
||||
|
||||
serializers.input.pages.browse(apiConfig, frame);
|
||||
frame.options.columns.should.eql(['id', 'visibility']);
|
||||
});
|
||||
|
||||
it('strips mobiledoc and lexical columns from a specified selectRaw option', function () {
|
||||
const apiConfig = {};
|
||||
const frame = {
|
||||
apiType: 'content',
|
||||
options: {
|
||||
context: {},
|
||||
selectRaw: 'id, mobiledoc, lexical'
|
||||
}
|
||||
};
|
||||
|
||||
serializers.input.posts.browse(apiConfig, frame);
|
||||
frame.options.selectRaw.should.eql('id');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('read', function () {
|
||||
|
Loading…
Reference in New Issue
Block a user