diff --git a/.changeset/two-buckets-do.md b/.changeset/two-buckets-do.md new file mode 100644 index 0000000000..0f7652dcfa --- /dev/null +++ b/.changeset/two-buckets-do.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend': patch +--- + +Allow max page limit for search results to be configurable diff --git a/plugins/search-backend/config.d.ts b/plugins/search-backend/config.d.ts index 99f4d0ab2f..3dbdf78dfe 100644 --- a/plugins/search-backend/config.d.ts +++ b/plugins/search-backend/config.d.ts @@ -17,6 +17,11 @@ export interface Config { /** Configuration options for the search plugin */ search?: { + /** + * Sets the maximum max page limit size. Defaults to 100. + */ + maxPageLimit?: number; + /** * Options related to the search integration with the Backstage permissions system */ diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index 6032f1af79..8840955c1a 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -48,6 +48,7 @@ "supertest": "^6.1.3" }, "files": [ - "dist" + "dist", + "config.d.ts" ] } diff --git a/plugins/search-backend/src/service/router.test.ts b/plugins/search-backend/src/service/router.test.ts index c3eb6ea00f..1dbd145bce 100644 --- a/plugins/search-backend/src/service/router.test.ts +++ b/plugins/search-backend/src/service/router.test.ts @@ -59,7 +59,10 @@ describe('createRouter', () => { 'first-type': {}, 'second-type': {}, }, - config: new ConfigReader({ permissions: { enabled: false } }), + config: new ConfigReader({ + permissions: { enabled: false }, + search: { maxPageLimit: 200 }, + }), permissions: mockPermissionEvaluator, logger, }); @@ -112,8 +115,8 @@ describe('createRouter', () => { }); }); - it('should accept per page value under or equal to 100', async () => { - const response = await request(app).get(`/query?pageLimit=30`); + it('should accept per page value under or equal to configured max', async () => { + const response = await request(app).get(`/query?pageLimit=200`); expect(response.status).toEqual(200); expect(response.body).toMatchObject({ @@ -121,13 +124,13 @@ describe('createRouter', () => { }); }); - it('should reject per page value over 100', async () => { - const response = await request(app).get(`/query?pageLimit=200`); + it('should reject per page value over configured max', async () => { + const response = await request(app).get(`/query?pageLimit=300`); expect(response.status).toEqual(400); expect(response.body).toMatchObject({ error: { - message: /The page limit "200" is greater than "100"/i, + message: /The page limit "300" is greater than "200"/i, }, }); }); diff --git a/plugins/search-backend/src/service/router.ts b/plugins/search-backend/src/service/router.ts index 0100c35e1d..b51dcead14 100644 --- a/plugins/search-backend/src/service/router.ts +++ b/plugins/search-backend/src/service/router.ts @@ -62,7 +62,7 @@ export type RouterOptions = { logger: Logger; }; -const maxPageLimit = 100; +const defaultMaxPageLimit = 100; const allowedLocationProtocols = ['http:', 'https:']; /** @@ -73,6 +73,9 @@ export async function createRouter( ): Promise { const { engine: inputEngine, types, permissions, config, logger } = options; + const maxPageLimit = + config.getOptionalNumber('search.maxPageLimit') ?? defaultMaxPageLimit; + const requestSchema = z.object({ term: z.string().default(''), filters: jsonObjectSchema.optional(),