diff --git a/src/lib/features/playground/advanced-playground.test.ts b/src/lib/features/playground/advanced-playground.test.ts index 44ba2807e0..a32713a0b1 100644 --- a/src/lib/features/playground/advanced-playground.test.ts +++ b/src/lib/features/playground/advanced-playground.test.ts @@ -16,6 +16,7 @@ beforeAll(async () => { experimental: { flags: { advancedPlayground: true, + strictSchemaValidation: true, }, }, }, diff --git a/src/lib/features/playground/playground-service.ts b/src/lib/features/playground/playground-service.ts index d1b6d83b4c..18fabe8cf9 100644 --- a/src/lib/features/playground/playground-service.ts +++ b/src/lib/features/playground/playground-service.ts @@ -13,6 +13,8 @@ import { FeatureConfigurationClient } from '../../types/stores/feature-strategie import { generateObjectCombinations } from './generateObjectCombinations'; import groupBy from 'lodash.groupby'; import { omitKeys } from '../../util'; +import { AdvancedPlaygroundFeatureSchema } from '../../openapi/spec/advanced-playground-feature-schema'; +import { AdvancedPlaygroundEnvironmentFeatureSchema } from '../../openapi/spec/advanced-playground-environment-feature-schema'; type EvaluationInput = { features: FeatureConfigurationClient[]; @@ -22,11 +24,6 @@ type EvaluationInput = { environment: string; }; -type AdvancedPlaygroundFeatureSchema = PlaygroundFeatureSchema & { - context: SdkContextSchema; - environment: string; -}; - export class PlaygroundService { private readonly logger: Logger; @@ -50,7 +47,7 @@ export class PlaygroundService { projects: typeof ALL | string[], environments: string[], context: SdkContextSchema, - ): Promise { + ): Promise { const segments = await this.segmentService.getActive(); const environmentFeatures = await Promise.all( environments.map((env) => this.resolveFeatures(projects, env)), @@ -73,14 +70,14 @@ export class PlaygroundService { ); const items = results.flat(); const itemsByName = groupBy(items, (item) => item.name); - return Object.entries(itemsByName).map(([name, entries]) => { + return Object.values(itemsByName).map((entries) => { const groupedEnvironments = groupBy( entries, (entry) => entry.environment, ); return { - name, - projectId: entries[0]?.projectId, + name: entries[0].name, + projectId: entries[0].projectId, environments: groupedEnvironments, }; }); @@ -92,7 +89,7 @@ export class PlaygroundService { segments, context, environment, - }: EvaluationInput): Promise { + }: EvaluationInput): Promise { const [head, ...rest] = features; if (!head) { return []; diff --git a/src/lib/features/playground/playground.test.ts b/src/lib/features/playground/playground.test.ts index bc6d0a3d93..24dd2eb01e 100644 --- a/src/lib/features/playground/playground.test.ts +++ b/src/lib/features/playground/playground.test.ts @@ -20,6 +20,7 @@ async function getSetup() { const stores = createStores(); const config = createTestConfig({ server: { baseUriPath: base }, + experimental: { flags: { strictSchemaValidation: true } }, }); const services = createServices(stores, config); const app = await getApp(config, stores, services); diff --git a/src/lib/features/playground/playground.ts b/src/lib/features/playground/playground.ts index 22f18292de..eb21177bbc 100644 --- a/src/lib/features/playground/playground.ts +++ b/src/lib/features/playground/playground.ts @@ -15,6 +15,8 @@ import { import { PlaygroundRequestSchema } from '../../openapi/spec/playground-request-schema'; import { PlaygroundService } from './playground-service'; import { IFlagResolver } from '../../types'; +import { AdvancedPlaygroundRequestSchema } from '../../openapi/spec/advanced-playground-request-schema'; +import { AdvancedPlaygroundResponseSchema } from '../../openapi/spec/advanced-playground-response-schema'; export default class PlaygroundController extends Controller { private openApiService: OpenApiService; @@ -59,7 +61,22 @@ export default class PlaygroundController extends Controller { path: '/advanced', handler: this.evaluateAdvancedContext, permission: NONE, - middleware: [], + middleware: [ + openApiService.validPath({ + operationId: 'getAdvancedPlayground', + tags: ['Unstable'], + responses: { + ...getStandardResponses(400, 401), + 200: createResponseSchema( + 'advancedPlaygroundResponseSchema', + ), + }, + requestBody: createRequestSchema( + 'advancedPlaygroundRequestSchema', + ), + ...endpointDescriptions.admin.advancedPlayground, + }), + ], }); } @@ -85,8 +102,8 @@ export default class PlaygroundController extends Controller { } async evaluateAdvancedContext( - req: Request, - res: Response, + req: Request, + res: Response, ): Promise { if (this.flagResolver.isEnabled('advancedPlayground')) { res.json({ diff --git a/src/lib/openapi/endpoint-descriptions.ts b/src/lib/openapi/endpoint-descriptions.ts index 75c9f689db..1eeb92b226 100644 --- a/src/lib/openapi/endpoint-descriptions.ts +++ b/src/lib/openapi/endpoint-descriptions.ts @@ -17,5 +17,11 @@ export const endpointDescriptions = { summary: 'Evaluate an Unleash context against a set of environments and projects.', }, + advancedPlayground: { + description: + 'Use the provided `context`, `environments`, and `projects` to evaluate toggles on this Unleash instance. You can use comma-separated values to provide multiple values to each context field. Returns a combinatorial list of all toggles that match the parameters and what they evaluate to. The response also contains the input parameters that were provided.', + summary: + 'Batch evaluate an Unleash context against a set of environments and projects.', + }, }, } as const; diff --git a/src/lib/openapi/index.ts b/src/lib/openapi/index.ts index f2ce9e8fc0..4e471b7f82 100644 --- a/src/lib/openapi/index.ts +++ b/src/lib/openapi/index.ts @@ -7,6 +7,8 @@ import { addonTypeSchema, adminCountSchema, adminFeaturesQuerySchema, + advancedPlaygroundRequestSchema, + advancedPlaygroundResponseSchema, apiTokenSchema, apiTokensSchema, applicationSchema, @@ -138,6 +140,7 @@ import { variantFlagSchema, variantsSchema, versionSchema, + advancedPlaygroundFeatureSchema, } from './spec'; import { IServerOption } from '../types'; import { mapValues, omitKeys } from '../util'; @@ -153,6 +156,7 @@ import { updateTagsSchema } from './spec/update-tags-schema'; import { batchStaleSchema } from './spec/batch-stale-schema'; import { createApplicationSchema } from './spec/create-application-schema'; import { contextFieldStrategiesSchema } from './spec/context-field-strategies-schema'; +import { advancedPlaygroundEnvironmentFeatureSchema } from './spec/advanced-playground-environment-feature-schema'; // Schemas must have an $id property on the form "#/components/schemas/mySchema". export type SchemaId = typeof schemas[keyof typeof schemas]['$id']; @@ -191,6 +195,10 @@ export const schemas: UnleashSchemas = { addonCreateUpdateSchema, addonsSchema, addonTypeSchema, + advancedPlaygroundEnvironmentFeatureSchema, + advancedPlaygroundFeatureSchema, + advancedPlaygroundRequestSchema, + advancedPlaygroundResponseSchema, apiTokenSchema, apiTokensSchema, applicationSchema, diff --git a/src/lib/openapi/meta-schema-rules.test.ts b/src/lib/openapi/meta-schema-rules.test.ts index ccc1d73f67..45d99af20d 100644 --- a/src/lib/openapi/meta-schema-rules.test.ts +++ b/src/lib/openapi/meta-schema-rules.test.ts @@ -123,8 +123,6 @@ const metaRules: Rule[] = [ 'passwordSchema', 'patchSchema', 'permissionSchema', - 'playgroundFeatureSchema', - 'playgroundRequestSchema', 'profileSchema', 'projectSchema', 'projectsSchema', diff --git a/src/lib/openapi/spec/advanced-playground-environment-feature-schema.ts b/src/lib/openapi/spec/advanced-playground-environment-feature-schema.ts new file mode 100644 index 0000000000..c3ca5df9d9 --- /dev/null +++ b/src/lib/openapi/spec/advanced-playground-environment-feature-schema.ts @@ -0,0 +1,156 @@ +import { FromSchema } from 'json-schema-to-ts'; +import { parametersSchema } from './parameters-schema'; +import { variantSchema } from './variant-schema'; +import { overrideSchema } from './override-schema'; +import { + playgroundStrategyEvaluation, + playgroundStrategySchema, +} from './playground-strategy-schema'; +import { playgroundConstraintSchema } from './playground-constraint-schema'; +import { playgroundSegmentSchema } from './playground-segment-schema'; +import { sdkContextSchema } from './sdk-context-schema'; + +export const advancedPlaygroundEnvironmentFeatureSchema = { + $id: '#/components/schemas/advancedPlaygroundEnvironmentFeatureSchema', + description: + 'A simplified feature toggle model intended for the Unleash playground.', + type: 'object', + additionalProperties: false, + required: [ + 'name', + 'environment', + 'context', + 'projectId', + 'isEnabled', + 'isEnabledInCurrentEnvironment', + 'variant', + 'variants', + 'strategies', + ], + properties: { + name: { + type: 'string', + example: 'my-feature', + description: "The feature's name.", + }, + environment: { + type: 'string', + example: 'development', + description: "The feature's environment.", + }, + context: { + description: 'The context to use when evaluating toggles', + $ref: sdkContextSchema.$id, + }, + projectId: { + type: 'string', + example: 'my-project', + description: 'The ID of the project that contains this feature.', + }, + strategies: { + type: 'object', + additionalProperties: false, + required: ['result', 'data'], + description: + "Feature's applicable strategies and cumulative results of the strategies", + properties: { + result: { + description: `The cumulative results of all the feature's strategies. Can be \`true\`, + \`false\`, or \`${playgroundStrategyEvaluation.unknownResult}\`. + This property will only be \`${playgroundStrategyEvaluation.unknownResult}\` + if one or more of the strategies can't be fully evaluated and the rest of the strategies + all resolve to \`false\`.`, + anyOf: [ + { type: 'boolean' }, + { + type: 'string', + enum: [playgroundStrategyEvaluation.unknownResult], + }, + ], + }, + data: { + description: 'The strategies that apply to this feature.', + type: 'array', + items: { + $ref: playgroundStrategySchema.$id, + }, + }, + }, + }, + isEnabledInCurrentEnvironment: { + type: 'boolean', + description: + 'Whether the feature is active and would be evaluated in the provided environment in a normal SDK context.', + }, + isEnabled: { + description: `Whether this feature is enabled or not in the current environment. + If a feature can't be fully evaluated (that is, \`strategies.result\` is \`${playgroundStrategyEvaluation.unknownResult}\`), + this will be \`false\` to align with how client SDKs treat unresolved feature states.`, + type: 'boolean', + example: true, + }, + variant: { + description: `The feature variant you receive based on the provided context or the _disabled + variant_. If a feature is disabled or doesn't have any + variants, you would get the _disabled variant_. + Otherwise, you'll get one of thefeature's defined variants.`, + type: 'object', + additionalProperties: false, + required: ['name', 'enabled'], + properties: { + name: { + type: 'string', + description: + "The variant's name. If there is no variant or if the toggle is disabled, this will be `disabled`", + example: 'red-variant', + }, + enabled: { + type: 'boolean', + description: + "Whether the variant is enabled or not. If the feature is disabled or if it doesn't have variants, this property will be `false`", + }, + payload: { + type: 'object', + additionalProperties: false, + required: ['type', 'value'], + description: 'An optional payload attached to the variant.', + properties: { + type: { + description: 'The format of the payload.', + type: 'string', + enum: ['json', 'csv', 'string'], + }, + value: { + type: 'string', + description: 'The payload value stringified.', + example: '{"property": "value"}', + }, + }, + }, + }, + nullable: true, + example: { name: 'green', enabled: true }, + }, + variants: { + type: 'array', + description: 'The feature variants.', + items: { $ref: variantSchema.$id }, + }, + }, + components: { + schemas: { + playgroundStrategySchema, + playgroundConstraintSchema, + playgroundSegmentSchema, + parametersSchema, + variantSchema, + overrideSchema, + sdkContextSchema, + }, + variants: { type: 'array', items: { $ref: variantSchema.$id } }, + }, +} as const; + +export type AdvancedPlaygroundEnvironmentFeatureSchema = FromSchema< + typeof advancedPlaygroundEnvironmentFeatureSchema +>; diff --git a/src/lib/openapi/spec/advanced-playground-feature-schema.ts b/src/lib/openapi/spec/advanced-playground-feature-schema.ts new file mode 100644 index 0000000000..4df1fbe58f --- /dev/null +++ b/src/lib/openapi/spec/advanced-playground-feature-schema.ts @@ -0,0 +1,55 @@ +import { FromSchema } from 'json-schema-to-ts'; +import { parametersSchema } from './parameters-schema'; +import { variantSchema } from './variant-schema'; +import { overrideSchema } from './override-schema'; +import { playgroundStrategySchema } from './playground-strategy-schema'; +import { playgroundConstraintSchema } from './playground-constraint-schema'; +import { playgroundSegmentSchema } from './playground-segment-schema'; +import { sdkContextSchema } from './sdk-context-schema'; +import { advancedPlaygroundEnvironmentFeatureSchema } from './advanced-playground-environment-feature-schema'; + +export const advancedPlaygroundFeatureSchema = { + $id: '#/components/schemas/advancedPlaygroundFeatureSchema', + description: + 'A simplified feature toggle model intended for the Unleash playground.', + type: 'object', + additionalProperties: false, + required: ['name', 'projectId', 'environments'], + properties: { + name: { + type: 'string', + example: 'my-feature', + description: "The feature's name.", + }, + projectId: { + type: 'string', + example: 'my-project', + description: 'The ID of the project that contains this feature.', + }, + environments: { + type: 'object', + description: + 'The lists of features that have been evaluated grouped by environment.', + additionalProperties: { + type: 'array', + items: { $ref: advancedPlaygroundEnvironmentFeatureSchema.$id }, + }, + }, + }, + components: { + schemas: { + advancedPlaygroundEnvironmentFeatureSchema, + playgroundStrategySchema, + playgroundConstraintSchema, + playgroundSegmentSchema, + parametersSchema, + variantSchema, + overrideSchema, + sdkContextSchema, + }, + }, +} as const; + +export type AdvancedPlaygroundFeatureSchema = FromSchema< + typeof advancedPlaygroundFeatureSchema +>; diff --git a/src/lib/openapi/spec/advanced-playground-request-schema.ts b/src/lib/openapi/spec/advanced-playground-request-schema.ts new file mode 100644 index 0000000000..b19ddd98d4 --- /dev/null +++ b/src/lib/openapi/spec/advanced-playground-request-schema.ts @@ -0,0 +1,48 @@ +import { FromSchema } from 'json-schema-to-ts'; +import { ALL } from '../../types/models/api-token'; +import { sdkContextSchema } from './sdk-context-schema'; + +export const advancedPlaygroundRequestSchema = { + $id: '#/components/schemas/advancedPlaygroundRequestSchema', + description: + 'Data for the playground API to evaluate toggles in advanced mode with environment and context multi selection', + type: 'object', + required: ['environments', 'context'], + properties: { + environments: { + type: 'array', + items: { type: 'string' }, + example: ['development', 'production'], + description: 'The environments to evaluate toggles in.', + }, + projects: { + description: 'A list of projects to check for toggles in.', + oneOf: [ + { + type: 'array', + items: { type: 'string' }, + example: ['my-project'], + description: 'A list of projects to check for toggles in.', + }, + { + type: 'string', + enum: [ALL], + description: 'Check toggles in all projects.', + }, + ], + }, + context: { + description: 'The context to use when evaluating toggles', + $ref: sdkContextSchema.$id, + }, + }, + components: { + schemas: { + sdkContextSchema, + }, + }, +} as const; + +export type AdvancedPlaygroundRequestSchema = FromSchema< + typeof advancedPlaygroundRequestSchema +>; diff --git a/src/lib/openapi/spec/advanced-playground-response-schema.ts b/src/lib/openapi/spec/advanced-playground-response-schema.ts new file mode 100644 index 0000000000..9ef005351d --- /dev/null +++ b/src/lib/openapi/spec/advanced-playground-response-schema.ts @@ -0,0 +1,52 @@ +import { FromSchema } from 'json-schema-to-ts'; +import { sdkContextSchema } from './sdk-context-schema'; +import { constraintSchema } from './constraint-schema'; +import { parametersSchema } from './parameters-schema'; +import { variantSchema } from './variant-schema'; +import { overrideSchema } from './override-schema'; +import { playgroundConstraintSchema } from './playground-constraint-schema'; +import { playgroundSegmentSchema } from './playground-segment-schema'; +import { playgroundStrategySchema } from './playground-strategy-schema'; +import { advancedPlaygroundRequestSchema } from './advanced-playground-request-schema'; +import { advancedPlaygroundFeatureSchema } from './advanced-playground-feature-schema'; +import { advancedPlaygroundEnvironmentFeatureSchema } from './advanced-playground-environment-feature-schema'; + +export const advancedPlaygroundResponseSchema = { + $id: '#/components/schemas/advancedPlaygroundResponseSchema', + description: 'The state of all features given the provided input.', + type: 'object', + additionalProperties: false, + required: ['features', 'input'], + properties: { + input: { + description: 'The given input used to evaluate the features.', + $ref: advancedPlaygroundRequestSchema.$id, + }, + features: { + type: 'array', + description: 'The list of features that have been evaluated.', + items: { + $ref: advancedPlaygroundFeatureSchema.$id, + }, + }, + }, + components: { + schemas: { + constraintSchema, + parametersSchema, + playgroundConstraintSchema, + advancedPlaygroundFeatureSchema, + advancedPlaygroundEnvironmentFeatureSchema, + advancedPlaygroundRequestSchema, + playgroundSegmentSchema, + playgroundStrategySchema, + sdkContextSchema, + variantSchema, + overrideSchema, + }, + }, +} as const; + +export type AdvancedPlaygroundResponseSchema = FromSchema< + typeof advancedPlaygroundResponseSchema +>; diff --git a/src/lib/openapi/spec/index.ts b/src/lib/openapi/spec/index.ts index e5793bcee8..479e0f887d 100644 --- a/src/lib/openapi/spec/index.ts +++ b/src/lib/openapi/spec/index.ts @@ -137,3 +137,6 @@ export * from './batch-features-schema'; export * from './token-string-list-schema'; export * from './bulk-toggle-features-schema'; export * from './admin-count-schema'; +export * from './advanced-playground-feature-schema'; +export * from './advanced-playground-response-schema'; +export * from './advanced-playground-request-schema'; diff --git a/src/lib/openapi/spec/playground-feature-schema.ts b/src/lib/openapi/spec/playground-feature-schema.ts index 0c18be5891..10ea359f85 100644 --- a/src/lib/openapi/spec/playground-feature-schema.ts +++ b/src/lib/openapi/spec/playground-feature-schema.ts @@ -41,6 +41,8 @@ export const playgroundFeatureSchema = { type: 'object', additionalProperties: false, required: ['result', 'data'], + description: + "The feature's applicable strategies and cumulative results of the strategies", properties: { result: { description: `The cumulative results of all the feature's strategies. Can be \`true\`, @@ -119,7 +121,11 @@ export const playgroundFeatureSchema = { nullable: true, example: { name: 'green', enabled: true }, }, - variants: { type: 'array', items: { $ref: variantSchema.$id } }, + variants: { + type: 'array', + description: 'The feature variants.', + items: { $ref: variantSchema.$id }, + }, }, components: { schemas: { diff --git a/src/lib/openapi/spec/playground-request-schema.ts b/src/lib/openapi/spec/playground-request-schema.ts index 9ac53c9d94..87f8c5546d 100644 --- a/src/lib/openapi/spec/playground-request-schema.ts +++ b/src/lib/openapi/spec/playground-request-schema.ts @@ -14,6 +14,7 @@ export const playgroundRequestSchema = { description: 'The environment to evaluate toggles in.', }, projects: { + description: 'A list of projects to check for toggles in.', oneOf: [ { type: 'array', diff --git a/src/lib/openapi/spec/sdk-context-schema.ts b/src/lib/openapi/spec/sdk-context-schema.ts index 62f259152a..59b6b48e40 100644 --- a/src/lib/openapi/spec/sdk-context-schema.ts +++ b/src/lib/openapi/spec/sdk-context-schema.ts @@ -11,13 +11,20 @@ export const sdkContextSchema = { type: 'string', minLength: 1, example: 'My cool application.', + description: 'The name of the application.', }, currentTime: { type: 'string', format: 'date-time', example: '2022-07-05T12:56:41+02:00', + description: + 'A DateTime (or similar) data class instance or a string in an RFC3339-compatible format. Defaults to the current time if not set by the user.', + }, + environment: { + type: 'string', + deprecated: true, + description: 'The environment the app is running in.', }, - environment: { type: 'string', deprecated: true }, properties: { type: 'object', additionalProperties: { type: 'string' }, @@ -29,12 +36,18 @@ export const sdkContextSchema = { remoteAddress: { type: 'string', example: '192.168.1.1', + description: "The app's IP address", }, sessionId: { type: 'string', example: 'b65e7b23-fec0-4814-a129-0e9861ef18fc', + description: 'An identifier for the current session', + }, + userId: { + type: 'string', + example: 'username@provider.com', + description: 'An identifier for the current user', }, - userId: { type: 'string', example: 'username@provider.com' }, }, components: {}, } as const; diff --git a/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap b/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap index b82828fc0b..98dc08541e 100644 --- a/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap +++ b/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap @@ -654,6 +654,251 @@ The provider you choose for your addon dictates what properties the \`parameters }, "type": "object", }, + "advancedPlaygroundEnvironmentFeatureSchema": { + "additionalProperties": false, + "description": "A simplified feature toggle model intended for the Unleash playground.", + "properties": { + "context": { + "$ref": "#/components/schemas/sdkContextSchema", + "description": "The context to use when evaluating toggles", + }, + "environment": { + "description": "The feature's environment.", + "example": "development", + "type": "string", + }, + "isEnabled": { + "description": "Whether this feature is enabled or not in the current environment. + If a feature can't be fully evaluated (that is, \`strategies.result\` is \`unknown\`), + this will be \`false\` to align with how client SDKs treat unresolved feature states.", + "example": true, + "type": "boolean", + }, + "isEnabledInCurrentEnvironment": { + "description": "Whether the feature is active and would be evaluated in the provided environment in a normal SDK context.", + "type": "boolean", + }, + "name": { + "description": "The feature's name.", + "example": "my-feature", + "type": "string", + }, + "projectId": { + "description": "The ID of the project that contains this feature.", + "example": "my-project", + "type": "string", + }, + "strategies": { + "additionalProperties": false, + "description": "Feature's applicable strategies and cumulative results of the strategies", + "properties": { + "data": { + "description": "The strategies that apply to this feature.", + "items": { + "$ref": "#/components/schemas/playgroundStrategySchema", + }, + "type": "array", + }, + "result": { + "anyOf": [ + { + "type": "boolean", + }, + { + "enum": [ + "unknown", + ], + "type": "string", + }, + ], + "description": "The cumulative results of all the feature's strategies. Can be \`true\`, + \`false\`, or \`unknown\`. + This property will only be \`unknown\` + if one or more of the strategies can't be fully evaluated and the rest of the strategies + all resolve to \`false\`.", + }, + }, + "required": [ + "result", + "data", + ], + "type": "object", + }, + "variant": { + "additionalProperties": false, + "description": "The feature variant you receive based on the provided context or the _disabled + variant_. If a feature is disabled or doesn't have any + variants, you would get the _disabled variant_. + Otherwise, you'll get one of thefeature's defined variants.", + "example": { + "enabled": true, + "name": "green", + }, + "nullable": true, + "properties": { + "enabled": { + "description": "Whether the variant is enabled or not. If the feature is disabled or if it doesn't have variants, this property will be \`false\`", + "type": "boolean", + }, + "name": { + "description": "The variant's name. If there is no variant or if the toggle is disabled, this will be \`disabled\`", + "example": "red-variant", + "type": "string", + }, + "payload": { + "additionalProperties": false, + "description": "An optional payload attached to the variant.", + "properties": { + "type": { + "description": "The format of the payload.", + "enum": [ + "json", + "csv", + "string", + ], + "type": "string", + }, + "value": { + "description": "The payload value stringified.", + "example": "{"property": "value"}", + "type": "string", + }, + }, + "required": [ + "type", + "value", + ], + "type": "object", + }, + }, + "required": [ + "name", + "enabled", + ], + "type": "object", + }, + "variants": { + "description": "The feature variants.", + "items": { + "$ref": "#/components/schemas/variantSchema", + }, + "type": "array", + }, + }, + "required": [ + "name", + "environment", + "context", + "projectId", + "isEnabled", + "isEnabledInCurrentEnvironment", + "variant", + "variants", + "strategies", + ], + "type": "object", + }, + "advancedPlaygroundFeatureSchema": { + "additionalProperties": false, + "description": "A simplified feature toggle model intended for the Unleash playground.", + "properties": { + "environments": { + "additionalProperties": { + "items": { + "$ref": "#/components/schemas/advancedPlaygroundEnvironmentFeatureSchema", + }, + "type": "array", + }, + "description": "The lists of features that have been evaluated grouped by environment.", + "type": "object", + }, + "name": { + "description": "The feature's name.", + "example": "my-feature", + "type": "string", + }, + "projectId": { + "description": "The ID of the project that contains this feature.", + "example": "my-project", + "type": "string", + }, + }, + "required": [ + "name", + "projectId", + "environments", + ], + "type": "object", + }, + "advancedPlaygroundRequestSchema": { + "description": "Data for the playground API to evaluate toggles in advanced mode with environment and context multi selection", + "properties": { + "context": { + "$ref": "#/components/schemas/sdkContextSchema", + "description": "The context to use when evaluating toggles", + }, + "environments": { + "description": "The environments to evaluate toggles in.", + "example": [ + "development", + "production", + ], + "items": { + "type": "string", + }, + "type": "array", + }, + "projects": { + "description": "A list of projects to check for toggles in.", + "oneOf": [ + { + "description": "A list of projects to check for toggles in.", + "example": [ + "my-project", + ], + "items": { + "type": "string", + }, + "type": "array", + }, + { + "description": "Check toggles in all projects.", + "enum": [ + "*", + ], + "type": "string", + }, + ], + }, + }, + "required": [ + "environments", + "context", + ], + "type": "object", + }, + "advancedPlaygroundResponseSchema": { + "additionalProperties": false, + "description": "The state of all features given the provided input.", + "properties": { + "features": { + "description": "The list of features that have been evaluated.", + "items": { + "$ref": "#/components/schemas/advancedPlaygroundFeatureSchema", + }, + "type": "array", + }, + "input": { + "$ref": "#/components/schemas/advancedPlaygroundRequestSchema", + "description": "The given input used to evaluate the features.", + }, + }, + "required": [ + "features", + "input", + ], + "type": "object", + }, "apiTokenSchema": { "additionalProperties": false, "description": "An overview of an [Unleash API token](https://docs.getunleash.io/reference/api-tokens-and-client-keys).", @@ -3494,6 +3739,7 @@ The provider you choose for your addon dictates what properties the \`parameters }, "strategies": { "additionalProperties": false, + "description": "The feature's applicable strategies and cumulative results of the strategies", "properties": { "data": { "description": "The strategies that apply to this feature.", @@ -3581,6 +3827,7 @@ The provider you choose for your addon dictates what properties the \`parameters "type": "object", }, "variants": { + "description": "The feature variants.", "items": { "$ref": "#/components/schemas/variantSchema", }, @@ -3611,6 +3858,7 @@ The provider you choose for your addon dictates what properties the \`parameters "type": "string", }, "projects": { + "description": "A list of projects to check for toggles in.", "oneOf": [ { "description": "A list of projects to check for toggles in.", @@ -4494,17 +4742,20 @@ Stats are divided into current and previous **windows**. "description": "The Unleash context as modeled in client SDKs", "properties": { "appName": { + "description": "The name of the application.", "example": "My cool application.", "minLength": 1, "type": "string", }, "currentTime": { + "description": "A DateTime (or similar) data class instance or a string in an RFC3339-compatible format. Defaults to the current time if not set by the user.", "example": "2022-07-05T12:56:41+02:00", "format": "date-time", "type": "string", }, "environment": { "deprecated": true, + "description": "The environment the app is running in.", "type": "string", }, "properties": { @@ -4518,14 +4769,17 @@ Stats are divided into current and previous **windows**. "type": "object", }, "remoteAddress": { + "description": "The app's IP address", "example": "192.168.1.1", "type": "string", }, "sessionId": { + "description": "An identifier for the current session", "example": "b65e7b23-fec0-4814-a129-0e9861ef18fc", "type": "string", }, "userId": { + "description": "An identifier for the current user", "example": "username@provider.com", "type": "string", }, @@ -9312,6 +9566,93 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9 ], }, }, + "/api/admin/playground/advanced": { + "post": { + "description": "Use the provided \`context\`, \`environments\`, and \`projects\` to evaluate toggles on this Unleash instance. You can use comma-separated values to provide multiple values to each context field. Returns a combinatorial list of all toggles that match the parameters and what they evaluate to. The response also contains the input parameters that were provided.", + "operationId": "getAdvancedPlayground", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/advancedPlaygroundRequestSchema", + }, + }, + }, + "description": "advancedPlaygroundRequestSchema", + "required": true, + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/advancedPlaygroundResponseSchema", + }, + }, + }, + "description": "advancedPlaygroundResponseSchema", + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "The request payload you provided doesn't conform to the schema. The .parameters property should be object. You sent [].", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "ValidationError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "The request data does not match what we expect.", + }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "description": "The ID of the error instance", + "example": "9c40958a-daac-400e-98fb-3bb438567008", + "type": "string", + }, + "message": { + "description": "A description of what went wrong.", + "example": "You must log in to use Unleash. Your request had no authorization header, so we could not authorize you. Try logging in at /auth/simple/login.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "AuthenticationRequired", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "Authorization information is missing or invalid. Provide a valid API token as the \`authorization\` header, e.g. \`authorization:*.*.my-admin-token\`.", + }, + }, + "summary": "Batch evaluate an Unleash context against a set of environments and projects.", + "tags": [ + "Unstable", + ], + }, + }, "/api/admin/projects": { "get": { "description": "This endpoint returns an list of all the projects in the Unleash instance.",