From 6363a3265fb99502cb0c562da01c82b1338c9965 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Fri, 5 Apr 2024 10:11:41 +0200 Subject: [PATCH] feat: add warnings to the api response --- .../playground/playground-api.e2e.test.ts | 27 +++++++++++++++++++ .../features/playground/playground-service.ts | 15 ++++++++--- .../playground/playground-view-model.ts | 5 ++++ src/lib/features/playground/playground.ts | 21 +++++++++------ .../advanced-playground-response-schema.ts | 14 ++++++++++ 5 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/lib/features/playground/playground-api.e2e.test.ts b/src/lib/features/playground/playground-api.e2e.test.ts index fd2d747cec..de13b37267 100644 --- a/src/lib/features/playground/playground-api.e2e.test.ts +++ b/src/lib/features/playground/playground-api.e2e.test.ts @@ -76,3 +76,30 @@ test('returns the input context exactly as it came in, even if invalid values ha expect(body.input.context).toMatchObject(inputContext); }); + +test('adds all removed top-level context properties to the list of warnings', async () => { + const invalidData = { + invalid1: {}, + invalid2: {}, + }; + + const inputContext = { + ...invalidData, + appName: 'test', + }; + + const { body } = await app.request + .post('/api/admin/playground/advanced') + .send({ + context: inputContext, + environments: ['production'], + projects: '*', + }) + .expect(200); + + const warned = body.warnings.invalidContextProperties; + const invalidKeys = Object.keys(invalidData); + + expect(warned).toEqual(expect.arrayContaining(invalidKeys)); + expect(invalidKeys).toEqual(expect.arrayContaining(warned)); +}); diff --git a/src/lib/features/playground/playground-service.ts b/src/lib/features/playground/playground-service.ts index 320090686c..dd3bc2b17f 100644 --- a/src/lib/features/playground/playground-service.ts +++ b/src/lib/features/playground/playground-service.ts @@ -103,7 +103,10 @@ export class PlaygroundService { context: SdkContextSchema, limit: number, userId: number, - ): Promise { + ): Promise<{ + result: AdvancedPlaygroundFeatureEvaluationResult[]; + invalidContextProperties: string[]; + }> { const segments = await this.segmentReadModel.getActive(); let filteredProjects: typeof projects = projects; @@ -126,7 +129,8 @@ export class PlaygroundService { ), ); - const { context: cleanedContext } = cleanContext(context); + const { context: cleanedContext, removedProperties } = + cleanContext(context); const contexts = generateObjectCombinations(cleanedContext); validateQueryComplexity( @@ -152,7 +156,7 @@ export class PlaygroundService { ); const items = results.flat(); const itemsByName = groupBy(items, (item) => item.name); - return Object.values(itemsByName).map((entries) => { + const result = Object.values(itemsByName).map((entries) => { const groupedEnvironments = groupBy( entries, (entry) => entry.environment, @@ -163,6 +167,11 @@ export class PlaygroundService { environments: groupedEnvironments, }; }); + + return { + result, + invalidContextProperties: removedProperties, + }; } private async evaluate({ diff --git a/src/lib/features/playground/playground-view-model.ts b/src/lib/features/playground/playground-view-model.ts index a7cdcce7e9..3996bc2d52 100644 --- a/src/lib/features/playground/playground-view-model.ts +++ b/src/lib/features/playground/playground-view-model.ts @@ -40,6 +40,7 @@ const addStrategyEditLink = ( export const advancedPlaygroundViewModel = ( input: AdvancedPlaygroundRequestSchema, playgroundResult: AdvancedPlaygroundFeatureEvaluationResult[], + invalidContextProperties: string[], ): AdvancedPlaygroundResponseSchema => { const features = playgroundResult.map(({ environments, ...rest }) => { const transformedEnvironments = Object.entries(environments).map( @@ -79,6 +80,10 @@ export const advancedPlaygroundViewModel = ( }; }); + if (invalidContextProperties.length > 0) { + return { features, input, warnings: { invalidContextProperties } }; + } + return { features, input }; }; diff --git a/src/lib/features/playground/playground.ts b/src/lib/features/playground/playground.ts index 41f5da2cd5..178929808a 100644 --- a/src/lib/features/playground/playground.ts +++ b/src/lib/features/playground/playground.ts @@ -125,16 +125,21 @@ export default class PlaygroundController extends Controller { ? Number.parseInt(payload?.value) : 15000; - const result = await this.playgroundService.evaluateAdvancedQuery( - req.body.projects || '*', - req.body.environments, - req.body.context, - limit, - extractUserIdFromUser(user), - ); + const { result, invalidContextProperties } = + await this.playgroundService.evaluateAdvancedQuery( + req.body.projects || '*', + req.body.environments, + req.body.context, + limit, + extractUserIdFromUser(user), + ); const response: AdvancedPlaygroundResponseSchema = - advancedPlaygroundViewModel(req.body, result); + advancedPlaygroundViewModel( + req.body, + result, + invalidContextProperties, + ); res.json(response); } diff --git a/src/lib/openapi/spec/advanced-playground-response-schema.ts b/src/lib/openapi/spec/advanced-playground-response-schema.ts index 9854a4c6af..b27bdf7b00 100644 --- a/src/lib/openapi/spec/advanced-playground-response-schema.ts +++ b/src/lib/openapi/spec/advanced-playground-response-schema.ts @@ -30,6 +30,20 @@ export const advancedPlaygroundResponseSchema = { $ref: advancedPlaygroundFeatureSchema.$id, }, }, + warnings: { + type: 'object', + description: 'Warnings that occurred during evaluation.', + properties: { + invalidContextProperties: { + type: 'array', + description: + 'A list of top-level context properties that were provided as input that are not valid due to being the wrong type.', + items: { + type: 'string', + }, + }, + }, + }, }, components: { schemas: {