diff --git a/src/lib/openapi/spec/__snapshots__/feature-schema.test.ts.snap b/src/lib/openapi/spec/__snapshots__/feature-schema.test.ts.snap index dda56808aa..a9439af3db 100644 --- a/src/lib/openapi/spec/__snapshots__/feature-schema.test.ts.snap +++ b/src/lib/openapi/spec/__snapshots__/feature-schema.test.ts.snap @@ -4,7 +4,7 @@ exports[`featureSchema constraints 1`] = ` { "errors": [ { - "instancePath": "/strategies/0/constraints/0", + "instancePath": "/environments/0/strategies/0/constraints/0", "keyword": "required", "message": "must have required property 'operator'", "params": { diff --git a/src/lib/openapi/spec/feature-environment-schema.test.ts b/src/lib/openapi/spec/feature-environment-schema.test.ts index 629118d23e..cd836c0cc2 100644 --- a/src/lib/openapi/spec/feature-environment-schema.test.ts +++ b/src/lib/openapi/spec/feature-environment-schema.test.ts @@ -8,10 +8,7 @@ test('featureEnvironmentSchema', () => { strategies: [ { id: '', - featureName: '', - projectId: '', - environment: '', - strategyName: '', + name: '', constraints: [{ contextName: '', operator: 'IN' }], parameters: { a: '' }, }, diff --git a/src/lib/openapi/spec/feature-environment-schema.ts b/src/lib/openapi/spec/feature-environment-schema.ts index 6c121094b8..30f95138e9 100644 --- a/src/lib/openapi/spec/feature-environment-schema.ts +++ b/src/lib/openapi/spec/feature-environment-schema.ts @@ -1,6 +1,7 @@ import { FromSchema } from 'json-schema-to-ts'; import { constraintSchema } from './constraint-schema'; import { parametersSchema } from './parameters-schema'; +import { featureStrategySchema } from './feature-strategy-schema'; export const featureEnvironmentSchema = { $id: '#/components/schemas/featureEnvironmentSchema', @@ -23,50 +24,7 @@ export const featureEnvironmentSchema = { strategies: { type: 'array', items: { - type: 'object', - additionalProperties: false, - required: [ - 'id', - 'featureName', - 'projectId', - 'environment', - 'strategyName', - 'constraints', - 'parameters', - ], - properties: { - id: { - type: 'string', - }, - featureName: { - type: 'string', - }, - projectId: { - type: 'string', - }, - environment: { - type: 'string', - }, - strategyName: { - type: 'string', - }, - sortOrder: { - type: 'number', - }, - createdAt: { - type: 'string', - format: 'date-time', - }, - constraints: { - type: 'array', - items: { - $ref: '#/components/schemas/constraintSchema', - }, - }, - parameters: { - $ref: '#/components/schemas/parametersSchema', - }, - }, + $ref: '#/components/schemas/featureStrategySchema', }, }, }, @@ -74,6 +32,7 @@ export const featureEnvironmentSchema = { schemas: { constraintSchema, parametersSchema, + featureStrategySchema, }, }, } as const; diff --git a/src/lib/openapi/spec/feature-schema.test.ts b/src/lib/openapi/spec/feature-schema.test.ts index 706051ac2a..cd72eeef57 100644 --- a/src/lib/openapi/spec/feature-schema.test.ts +++ b/src/lib/openapi/spec/feature-schema.test.ts @@ -4,19 +4,6 @@ import { FeatureSchema } from './feature-schema'; test('featureSchema', () => { const data: FeatureSchema = { name: 'a', - strategies: [ - { - id: 'a', - name: 'a', - constraints: [ - { - contextName: 'a', - operator: 'IN', - }, - ], - segments: [1], - }, - ], variants: [ { name: 'a', @@ -32,6 +19,19 @@ test('featureSchema', () => { name: 'a', type: 'b', enabled: true, + strategies: [ + { + id: 'a', + name: 'a', + constraints: [ + { + contextName: 'a', + operator: 'IN', + }, + ], + segments: [1], + }, + ], }, ], }; @@ -44,7 +44,16 @@ test('featureSchema', () => { test('featureSchema constraints', () => { const data = { name: 'a', - strategies: [{ name: 'a', constraints: [{ contextName: 'a' }] }], + environments: [ + { + name: 'a', + type: 'b', + enabled: true, + strategies: [ + { name: 'a', constraints: [{ contextName: 'a' }] }, + ], + }, + ], }; expect( diff --git a/src/lib/openapi/spec/feature-schema.ts b/src/lib/openapi/spec/feature-schema.ts index b00f52ab1b..d7dba80d1d 100644 --- a/src/lib/openapi/spec/feature-schema.ts +++ b/src/lib/openapi/spec/feature-schema.ts @@ -3,9 +3,9 @@ import { variantSchema } from './variant-schema'; import { constraintSchema } from './constraint-schema'; import { overrideSchema } from './override-schema'; import { parametersSchema } from './parameters-schema'; -import { environmentSchema } from './environment-schema'; import { featureStrategySchema } from './feature-strategy-schema'; import { tagSchema } from './tag-schema'; +import { featureEnvironmentSchema } from './feature-environment-schema'; export const featureSchema = { $id: '#/components/schemas/featureSchema', @@ -58,13 +58,7 @@ export const featureSchema = { environments: { type: 'array', items: { - $ref: '#/components/schemas/environmentSchema', - }, - }, - strategies: { - type: 'array', - items: { - $ref: '#/components/schemas/featureStrategySchema', + $ref: '#/components/schemas/featureEnvironmentSchema', }, }, variants: { @@ -84,10 +78,10 @@ export const featureSchema = { components: { schemas: { constraintSchema, - environmentSchema, + featureEnvironmentSchema, + featureStrategySchema, overrideSchema, parametersSchema, - featureStrategySchema, variantSchema, tagSchema, }, diff --git a/src/lib/openapi/spec/features-schema.ts b/src/lib/openapi/spec/features-schema.ts index 2ba977b45a..0a39777642 100644 --- a/src/lib/openapi/spec/features-schema.ts +++ b/src/lib/openapi/spec/features-schema.ts @@ -6,6 +6,7 @@ import { overrideSchema } from './override-schema'; import { constraintSchema } from './constraint-schema'; import { featureStrategySchema } from './feature-strategy-schema'; import { environmentSchema } from './environment-schema'; +import { featureEnvironmentSchema } from './feature-environment-schema'; export const featuresSchema = { $id: '#/components/schemas/featuresSchema', @@ -29,8 +30,9 @@ export const featuresSchema = { environmentSchema, featureSchema, overrideSchema, - parametersSchema, + featureEnvironmentSchema, featureStrategySchema, + parametersSchema, variantSchema, }, }, diff --git a/src/lib/openapi/spec/health-overview-schema.ts b/src/lib/openapi/spec/health-overview-schema.ts index e3a2956cb5..eadde2b1aa 100644 --- a/src/lib/openapi/spec/health-overview-schema.ts +++ b/src/lib/openapi/spec/health-overview-schema.ts @@ -6,6 +6,7 @@ import { featureStrategySchema } from './feature-strategy-schema'; import { featureSchema } from './feature-schema'; import { constraintSchema } from './constraint-schema'; import { environmentSchema } from './environment-schema'; +import { featureEnvironmentSchema } from './feature-environment-schema'; export const healthOverviewSchema = { $id: '#/components/schemas/healthOverviewSchema', @@ -54,6 +55,7 @@ export const healthOverviewSchema = { constraintSchema, environmentSchema, featureSchema, + featureEnvironmentSchema, overrideSchema, parametersSchema, featureStrategySchema, diff --git a/src/lib/routes/admin-api/project/features.ts b/src/lib/routes/admin-api/project/features.ts index c7678a9968..67d29e2261 100644 --- a/src/lib/routes/admin-api/project/features.ts +++ b/src/lib/routes/admin-api/project/features.ts @@ -1,11 +1,10 @@ import { Request, Response } from 'express'; import { applyPatch, Operation } from 'fast-json-patch'; import Controller from '../../controller'; -import { IUnleashConfig } from '../../../types/option'; -import { IUnleashServices } from '../../../types'; -import FeatureToggleService from '../../../services/feature-toggle-service'; -import { Logger } from '../../../logger'; import { + IUnleashConfig, + IUnleashServices, + serializeDates, CREATE_FEATURE, CREATE_FEATURE_STRATEGY, DELETE_FEATURE, @@ -14,37 +13,35 @@ import { UPDATE_FEATURE, UPDATE_FEATURE_ENVIRONMENT, UPDATE_FEATURE_STRATEGY, -} from '../../../types/permissions'; -import { extractUsername } from '../../../util/extract-user'; +} from '../../../types'; +import { Logger } from '../../../logger'; +import { extractUsername } from '../../../util'; import { IAuthRequest } from '../../unleash-types'; -import { CreateFeatureSchema } from '../../../openapi/spec/create-feature-schema'; import { + AdminFeaturesQuerySchema, + CreateFeatureSchema, + CreateFeatureStrategySchema, + createRequestSchema, + createResponseSchema, + emptyResponse, + FeatureEnvironmentSchema, featureSchema, FeatureSchema, -} from '../../../openapi/spec/feature-schema'; -import { FeatureStrategySchema } from '../../../openapi/spec/feature-strategy-schema'; -import { ParametersSchema } from '../../../openapi/spec/parameters-schema'; -import { featuresSchema, FeaturesSchema, -} from '../../../openapi/spec/features-schema'; -import { UpdateFeatureSchema } from '../../../openapi/spec/update-feature-schema'; -import { UpdateFeatureStrategySchema } from '../../../openapi/spec/update-feature-strategy-schema'; -import { CreateFeatureStrategySchema } from '../../../openapi/spec/create-feature-strategy-schema'; -import { serializeDates } from '../../../types/serialize-dates'; -import { OpenApiService } from '../../../services/openapi-service'; -import { createRequestSchema } from '../../../openapi/util/create-request-schema'; -import { createResponseSchema } from '../../../openapi/util/create-response-schema'; -import { FeatureEnvironmentSchema } from '../../../openapi/spec/feature-environment-schema'; -import { SetStrategySortOrderSchema } from '../../../openapi/spec/set-strategy-sort-order-schema'; - -import { - emptyResponse, + FeatureStrategySchema, getStandardResponses, -} from '../../../openapi/util/standard-responses'; -import { SegmentService } from '../../../services/segment-service'; + ParametersSchema, + SetStrategySortOrderSchema, + UpdateFeatureSchema, + UpdateFeatureStrategySchema, +} from '../../../openapi'; +import { + OpenApiService, + SegmentService, + FeatureToggleService, +} from '../../../services'; import { querySchema } from '../../../schema/feature-schema'; -import { AdminFeaturesQuerySchema } from '../../../openapi'; interface FeatureStrategyParams { projectId: string; @@ -589,11 +586,20 @@ export default class ProjectFeaturesController extends Controller { environment, featureName, ); + + const result = { + ...environmentInfo, + strategies: environmentInfo.strategies.map((strategy) => { + const { strategyName, ...rest } = strategy; + return { ...rest, name: strategyName }; + }), + }; + this.openApiService.respondWithValidation( 200, res, featureSchema.$id, - serializeDates(environmentInfo), + serializeDates(result), ); } 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 3fedeeb901..9485c181d0 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 @@ -1079,50 +1079,7 @@ exports[`should serve the OpenAPI spec 1`] = ` }, "strategies": { "items": { - "additionalProperties": false, - "properties": { - "constraints": { - "items": { - "$ref": "#/components/schemas/constraintSchema", - }, - "type": "array", - }, - "createdAt": { - "format": "date-time", - "type": "string", - }, - "environment": { - "type": "string", - }, - "featureName": { - "type": "string", - }, - "id": { - "type": "string", - }, - "parameters": { - "$ref": "#/components/schemas/parametersSchema", - }, - "projectId": { - "type": "string", - }, - "sortOrder": { - "type": "number", - }, - "strategyName": { - "type": "string", - }, - }, - "required": [ - "id", - "featureName", - "projectId", - "environment", - "strategyName", - "constraints", - "parameters", - ], - "type": "object", + "$ref": "#/components/schemas/featureStrategySchema", }, "type": "array", }, @@ -1204,7 +1161,7 @@ exports[`should serve the OpenAPI spec 1`] = ` }, "environments": { "items": { - "$ref": "#/components/schemas/environmentSchema", + "$ref": "#/components/schemas/featureEnvironmentSchema", }, "type": "array", }, @@ -1228,12 +1185,6 @@ exports[`should serve the OpenAPI spec 1`] = ` "stale": { "type": "boolean", }, - "strategies": { - "items": { - "$ref": "#/components/schemas/featureStrategySchema", - }, - "type": "array", - }, "tags": { "items": { "$ref": "#/components/schemas/tagSchema",