From 1b248a03e900f143222bba98b1f78b0fb94a0d05 Mon Sep 17 00:00:00 2001 From: Christopher Kolstad Date: Wed, 26 Apr 2023 12:10:57 +0200 Subject: [PATCH] docs: Metrics tag openapi docs (#3572) I've copied most of the descriptions from what we did for batch metrics under the Edge tag, however there are a couple of top level descriptions that are "fine" but I'm definitely open to suggestions. --------- Co-authored-by: Thomas Heartman --- .github/workflows/build_prs_jest_report.yaml | 2 +- src/lib/openapi/index.ts | 2 + src/lib/openapi/meta-schema-rules.test.ts | 11 - src/lib/openapi/spec/application-schema.ts | 21 +- src/lib/openapi/spec/applications-schema.ts | 3 + src/lib/openapi/spec/bulk-metrics-schema.ts | 3 + .../openapi/spec/client-metrics-env-schema.ts | 6 +- src/lib/openapi/spec/client-metrics-schema.ts | 63 ++- .../openapi/spec/create-application-schema.ts | 52 ++ .../feature-environment-metrics-schema.ts | 29 +- .../openapi/spec/feature-metrics-schema.ts | 11 +- src/lib/openapi/spec/feature-usage-schema.ts | 17 +- src/lib/routes/admin-api/client-metrics.ts | 8 + src/lib/routes/admin-api/metrics.ts | 25 +- .../__snapshots__/openapi.e2e.test.ts.snap | 488 +++++++++++++++++- 15 files changed, 693 insertions(+), 48 deletions(-) create mode 100644 src/lib/openapi/spec/create-application-schema.ts diff --git a/.github/workflows/build_prs_jest_report.yaml b/.github/workflows/build_prs_jest_report.yaml index 6709f5823b..9371bb9a2a 100644 --- a/.github/workflows/build_prs_jest_report.yaml +++ b/.github/workflows/build_prs_jest_report.yaml @@ -6,7 +6,7 @@ on: jobs: build: runs-on: ubuntu-latest - name: build (14.x) # temporary solution to trick branch protection rules + name: build (18.x) # temporary solution to trick branch protection rules services: # Label used to access the service container diff --git a/src/lib/openapi/index.ts b/src/lib/openapi/index.ts index 7a627ec304..052ebe0be8 100644 --- a/src/lib/openapi/index.ts +++ b/src/lib/openapi/index.ts @@ -148,6 +148,7 @@ import { bulkMetricsSchema } from './spec/bulk-metrics-schema'; import { clientMetricsEnvSchema } from './spec/client-metrics-env-schema'; import { updateTagsSchema } from './spec/update-tags-schema'; import { batchStaleSchema } from './spec/batch-stale-schema'; +import { createApplicationSchema } from './spec/create-application-schema'; // Schemas must have an $id property on the form "#/components/schemas/mySchema". export type SchemaId = typeof schemas[keyof typeof schemas]['$id']; @@ -205,6 +206,7 @@ export const schemas: UnleashSchemas = { contextFieldSchema, contextFieldsSchema, createApiTokenSchema, + createApplicationSchema, createFeatureSchema, createFeatureStrategySchema, createInvitedUserSchema, diff --git a/src/lib/openapi/meta-schema-rules.test.ts b/src/lib/openapi/meta-schema-rules.test.ts index 92a207d61c..8528c8580e 100644 --- a/src/lib/openapi/meta-schema-rules.test.ts +++ b/src/lib/openapi/meta-schema-rules.test.ts @@ -81,8 +81,6 @@ const metaRules: Rule[] = [ knownExceptions: [ 'apiTokenSchema', 'apiTokensSchema', - 'applicationSchema', - 'applicationsSchema', 'batchFeaturesSchema', 'batchStaleSchema', 'changePasswordSchema', @@ -90,8 +88,6 @@ const metaRules: Rule[] = [ 'clientFeatureSchema', 'clientFeaturesQuerySchema', 'clientFeaturesSchema', - 'clientMetricsSchema', - 'bulkMetricsSchema', 'cloneFeatureSchema', 'contextFieldSchema', 'createApiTokenSchema', @@ -105,17 +101,14 @@ const metaRules: Rule[] = [ 'eventsSchema', 'exportResultSchema', 'exportQuerySchema', - 'featureEnvironmentMetricsSchema', 'featureEnvironmentSchema', 'featureEventsSchema', - 'featureMetricsSchema', 'featureSchema', 'featuresSchema', 'featureStrategySchema', 'featureStrategySegmentSchema', 'featureTypeSchema', 'featureTypesSchema', - 'featureUsageSchema', 'featureVariantsSchema', 'feedbackSchema', 'groupSchema', @@ -206,7 +199,6 @@ const metaRules: Rule[] = [ 'clientFeatureSchema', 'clientFeaturesQuerySchema', 'clientFeaturesSchema', - 'clientMetricsSchema', 'cloneFeatureSchema', 'contextFieldSchema', 'contextFieldsSchema', @@ -222,15 +214,12 @@ const metaRules: Rule[] = [ 'eventsSchema', 'exportResultSchema', 'exportQuerySchema', - 'featureEnvironmentMetricsSchema', 'featureEventsSchema', - 'featureMetricsSchema', 'featureSchema', 'featuresSchema', 'featureStrategySegmentSchema', 'featureTypeSchema', 'featureTypesSchema', - 'featureUsageSchema', 'featureVariantsSchema', 'feedbackSchema', 'groupSchema', diff --git a/src/lib/openapi/spec/application-schema.ts b/src/lib/openapi/spec/application-schema.ts index db4f50a122..064f4aa58f 100644 --- a/src/lib/openapi/spec/application-schema.ts +++ b/src/lib/openapi/spec/application-schema.ts @@ -7,31 +7,46 @@ export const applicationSchema = { required: ['appName'], properties: { appName: { + description: 'Name of the application', type: 'string', + example: 'accounting', }, sdkVersion: { + description: + 'Which SDK and version the application reporting uses. Typically represented as `:`', type: 'string', + example: 'unleash-client-java:8.0.0', }, strategies: { + description: + 'Which [strategies](https://docs.getunleash.io/topics/the-anatomy-of-unleash#activation-strategies) the application has loaded. Useful when trying to figure out if your [custom strategy](https://docs.getunleash.io/reference/custom-activation-strategies) has been loaded in the SDK', type: 'array', items: { type: 'string', }, + example: ['standard', 'gradualRollout', 'mySpecialCustomStrategy'], }, description: { + description: + 'Extra information added about the application reporting the metrics. Only present if added via the Unleash Admin interface', type: 'string', + example: 'Application for reporting page visits', }, url: { + description: + 'A link to reference the application reporting the metrics. Could for instance be a GitHub link to the repository of the application', type: 'string', + example: 'https://github.com/Unleash/unleash-client-proxy-js', }, color: { + description: `The CSS color that is used to color the application's entry in the application list`, type: 'string', + example: 'red', }, icon: { + description: `An URL to an icon file to be used for the applications's entry in the application list`, type: 'string', - }, - announced: { - type: 'boolean', + example: 'https://github.com/favicon.ico', }, }, components: {}, diff --git a/src/lib/openapi/spec/applications-schema.ts b/src/lib/openapi/spec/applications-schema.ts index efda2f935a..294a456161 100644 --- a/src/lib/openapi/spec/applications-schema.ts +++ b/src/lib/openapi/spec/applications-schema.ts @@ -3,9 +3,12 @@ import { FromSchema } from 'json-schema-to-ts'; export const applicationsSchema = { $id: '#/components/schemas/applicationsSchema', + additionalProperties: false, type: 'object', properties: { applications: { + description: + 'Contains a list of applications that have connected via an SDK', type: 'array', items: { $ref: '#/components/schemas/applicationSchema', diff --git a/src/lib/openapi/spec/bulk-metrics-schema.ts b/src/lib/openapi/spec/bulk-metrics-schema.ts index acf7401086..7fc49fe5bd 100644 --- a/src/lib/openapi/spec/bulk-metrics-schema.ts +++ b/src/lib/openapi/spec/bulk-metrics-schema.ts @@ -11,12 +11,15 @@ export const bulkMetricsSchema = { 'A batch of metrics accumulated by Edge (or other compatible applications). Includes both application registrations as well usage metrics from clients', properties: { applications: { + description: 'A list of applications registered by an Unleash SDK', type: 'array', items: { $ref: '#/components/schemas/bulkRegistrationSchema', }, }, metrics: { + description: + 'a list of client usage metrics registered by downstream providers. (Typically Unleash Edge)', type: 'array', items: { $ref: '#/components/schemas/clientMetricsEnvSchema', diff --git a/src/lib/openapi/spec/client-metrics-env-schema.ts b/src/lib/openapi/spec/client-metrics-env-schema.ts index b449d1cc4e..7f75291978 100644 --- a/src/lib/openapi/spec/client-metrics-env-schema.ts +++ b/src/lib/openapi/spec/client-metrics-env-schema.ts @@ -31,13 +31,15 @@ export const clientMetricsEnvSchema = { }, yes: { description: 'How many times the toggle evaluated to true', - type: 'number', + type: 'integer', example: 974, + minimum: 0, }, no: { description: 'How many times the toggle evaluated to false', - type: 'number', + type: 'integer', example: 50, + minimum: 0, }, variants: { description: 'How many times each variant was returned', diff --git a/src/lib/openapi/spec/client-metrics-schema.ts b/src/lib/openapi/spec/client-metrics-schema.ts index c194c9a4d9..c6d12dcb97 100644 --- a/src/lib/openapi/spec/client-metrics-schema.ts +++ b/src/lib/openapi/spec/client-metrics-schema.ts @@ -5,18 +5,48 @@ export const clientMetricsSchema = { $id: '#/components/schemas/clientMetricsSchema', type: 'object', required: ['appName', 'bucket'], + description: + 'Client usage metrics, accumulated in buckets of hour by hour by default', properties: { - appName: { type: 'string' }, - instanceId: { type: 'string' }, - environment: { type: 'string' }, + appName: { + description: + 'The name of the application that is evaluating toggles', + type: 'string', + example: 'insurance-selector', + }, + instanceId: { + description: + 'A [(somewhat) unique identifier](https://docs.getunleash.io/reference/sdks/node#advanced-usage) for the application', + type: 'string', + example: 'application-name-dacb1234', + }, + environment: { + description: 'Which environment the application is running in', + type: 'string', + example: 'development', + }, bucket: { type: 'object', required: ['start', 'stop', 'toggles'], + description: + 'Holds all metrics gathered over a window of time. Typically 1 hour wide', properties: { - start: { $ref: '#/components/schemas/dateSchema' }, - stop: { $ref: '#/components/schemas/dateSchema' }, + start: { + $ref: '#/components/schemas/dateSchema', + description: + 'The start of the time window these metrics are valid for. The window is usually 1 hour wide', + example: '1926-05-08T12:00:00.000Z', + }, + stop: { + $ref: '#/components/schemas/dateSchema', + description: + 'The end of the time window these metrics are valid for. The window is 1 hour wide', + example: '1926-05-08T13:00:00.000Z', + }, toggles: { type: 'object', + description: + 'an object containing feature names with yes/no plus variant usage', example: { myCoolToggle: { yes: 25, @@ -35,14 +65,33 @@ export const clientMetricsSchema = { additionalProperties: { type: 'object', properties: { - yes: { type: 'integer', minimum: 0 }, - no: { type: 'integer', minimum: 0 }, + yes: { + description: + 'How many times the toggle evaluated to true', + type: 'number', + example: 974, + minimum: 0, + }, + no: { + description: + 'How many times the toggle evaluated to false', + type: 'integer', + example: 50, + minimum: 0, + }, variants: { + description: + 'How many times each variant was returned', type: 'object', additionalProperties: { type: 'integer', minimum: 0, }, + example: { + variantA: 15, + variantB: 25, + variantC: 5, + }, }, }, }, diff --git a/src/lib/openapi/spec/create-application-schema.ts b/src/lib/openapi/spec/create-application-schema.ts new file mode 100644 index 0000000000..edcac29957 --- /dev/null +++ b/src/lib/openapi/spec/create-application-schema.ts @@ -0,0 +1,52 @@ +import { FromSchema } from 'json-schema-to-ts'; + +export const createApplicationSchema = { + $id: '#/components/schemas/createApplicationSchema', + type: 'object', + additionalProperties: true, + description: 'Reported application information from Unleash SDKs', + required: ['appName'], + properties: { + appName: { + description: 'Name of the application', + type: 'string', + example: 'accounting', + }, + sdkVersion: { + description: + 'Which SDK and version the application reporting uses. Typically represented as `:`', + type: 'string', + example: 'unleash-client-java:8.0.0', + }, + strategies: { + description: + 'Which [strategies](https://docs.getunleash.io/topics/the-anatomy-of-unleash#activation-strategies) the application has loaded. Useful when trying to figure out if your [custom strategy](https://docs.getunleash.io/reference/custom-activation-strategies) has been loaded in the SDK', + type: 'array', + items: { + type: 'string', + }, + example: ['standard', 'gradualRollout', 'mySpecialCustomStrategy'], + }, + url: { + description: + 'A link to reference the application reporting the metrics. Could for instance be a GitHub link to the repository of the application', + type: 'string', + example: 'https://github.com/Unleash/unleash-client-proxy-js', + }, + color: { + description: `Css color to be used to color the application's entry in the application list`, + type: 'string', + example: 'red', + }, + icon: { + description: `An URL to an icon file to be used for the applications's entry in the application list`, + type: 'string', + example: 'https://github.com/favicon.ico', + }, + }, + components: {}, +} as const; + +export type CreateApplicationSchema = FromSchema< + typeof createApplicationSchema +>; diff --git a/src/lib/openapi/spec/feature-environment-metrics-schema.ts b/src/lib/openapi/spec/feature-environment-metrics-schema.ts index 50b54642e6..00a3b8690e 100644 --- a/src/lib/openapi/spec/feature-environment-metrics-schema.ts +++ b/src/lib/openapi/spec/feature-environment-metrics-schema.ts @@ -1,32 +1,51 @@ import { FromSchema } from 'json-schema-to-ts'; +import { dateSchema } from './date-schema'; export const featureEnvironmentMetricsSchema = { $id: '#/components/schemas/featureEnvironmentMetricsSchema', type: 'object', additionalProperties: false, required: ['environment', 'timestamp', 'yes', 'no'], + description: + 'How many times `feautreName` was evaluated to `true` (yes) and `false` (no) for `appName` in `environmnet`', properties: { featureName: { + description: 'The name of the feature', type: 'string', + example: 'my.special.feature', }, appName: { + description: 'The name of the application the SDK is being used in', type: 'string', + example: 'accounting', }, environment: { + description: 'Which environment the SDK is being used in', type: 'string', + example: 'development', }, timestamp: { - type: 'string', - format: 'date-time', + description: + 'The start of the time window these metrics are valid for. The window is usually 1 hour wide', + example: '1926-05-08T12:00:00.000Z', + $ref: '#/components/schemas/dateSchema', }, yes: { - type: 'number', + description: 'How many times the toggle evaluated to true', + type: 'integer', + example: 974, + minimum: 0, }, no: { - type: 'number', + description: 'How many times the toggle evaluated to false', + type: 'integer', + example: 50, + minimum: 0, }, }, - components: {}, + components: { + dateSchema, + }, } as const; export type FeatureEnvironmentMetricsSchema = FromSchema< diff --git a/src/lib/openapi/spec/feature-metrics-schema.ts b/src/lib/openapi/spec/feature-metrics-schema.ts index 06b5c40ed6..0eeb620003 100644 --- a/src/lib/openapi/spec/feature-metrics-schema.ts +++ b/src/lib/openapi/spec/feature-metrics-schema.ts @@ -1,19 +1,27 @@ import { FromSchema } from 'json-schema-to-ts'; import { featureEnvironmentMetricsSchema } from './feature-environment-metrics-schema'; +import { dateSchema } from './date-schema'; export const featureMetricsSchema = { $id: '#/components/schemas/featureMetricsSchema', type: 'object', additionalProperties: false, required: ['version', 'maturity', 'data'], + description: 'A batch of feature metrics', properties: { version: { - type: 'number', + description: 'The version of this schema', + type: 'integer', + minimum: 1, }, maturity: { + description: + 'The maturity level of this API (alpha, beta, stable, deprecated)', type: 'string', + example: 'stable', }, data: { + description: 'Metrics gathered per environment', type: 'array', items: { $ref: '#/components/schemas/featureEnvironmentMetricsSchema', @@ -23,6 +31,7 @@ export const featureMetricsSchema = { components: { schemas: { featureEnvironmentMetricsSchema, + dateSchema, }, }, } as const; diff --git a/src/lib/openapi/spec/feature-usage-schema.ts b/src/lib/openapi/spec/feature-usage-schema.ts index cb64af1fc5..e0d0d02192 100644 --- a/src/lib/openapi/spec/feature-usage-schema.ts +++ b/src/lib/openapi/spec/feature-usage-schema.ts @@ -1,10 +1,13 @@ import { FromSchema } from 'json-schema-to-ts'; import { featureEnvironmentMetricsSchema } from './feature-environment-metrics-schema'; +import { dateSchema } from './date-schema'; export const featureUsageSchema = { $id: '#/components/schemas/featureUsageSchema', type: 'object', additionalProperties: false, + description: + 'How many applications have seen this feature toggle, as well as how this feature was evaluated the last hour', required: [ 'version', 'maturity', @@ -14,30 +17,42 @@ export const featureUsageSchema = { ], properties: { version: { - type: 'number', + description: 'The version of this schema', + type: 'integer', + minimum: 1, }, maturity: { + description: + 'The maturity level of this API (alpha, beta, stable, deprecated)', type: 'string', + example: 'stable', }, featureName: { + description: 'The name of the feature', type: 'string', + example: 'my.special.feature', }, lastHourUsage: { + description: + 'Last hour statistics. Accumulated per feature per environment. Contains counts for evaluations to true (yes) and to false (no)', type: 'array', items: { $ref: '#/components/schemas/featureEnvironmentMetricsSchema', }, }, seenApplications: { + description: 'A list of applications seen using this feature', type: 'array', items: { type: 'string', }, + example: ['accounting', 'billing', 'booking'], }, }, components: { schemas: { featureEnvironmentMetricsSchema, + dateSchema, }, }, } as const; diff --git a/src/lib/routes/admin-api/client-metrics.ts b/src/lib/routes/admin-api/client-metrics.ts index cdc432515f..223b7ac304 100644 --- a/src/lib/routes/admin-api/client-metrics.ts +++ b/src/lib/routes/admin-api/client-metrics.ts @@ -16,6 +16,7 @@ import { featureMetricsSchema, FeatureMetricsSchema, } from '../../openapi/spec/feature-metrics-schema'; +import { getStandardResponses } from '../../openapi'; interface IName { name: string; @@ -58,8 +59,11 @@ class ClientMetricsController extends Controller { openApiService.validPath({ operationId: 'getRawFeatureMetrics', tags: ['Metrics'], + summary: + 'Feature usage metrics for the last 48 hours, grouped by hour', responses: { 200: createResponseSchema('featureMetricsSchema'), + ...getStandardResponses(401, 403, 404), }, }), ], @@ -74,8 +78,12 @@ class ClientMetricsController extends Controller { openApiService.validPath({ operationId: 'getFeatureUsageSummary', tags: ['Metrics'], + summary: `Last hour of usage and a list of applications that have reported seeing this feature toggle`, + description: + 'Separate counts for yes (enabled), no (disabled), as well as how many times each variant was selected during the last hour', responses: { 200: createResponseSchema('featureUsageSchema'), + ...getStandardResponses(401, 403, 404), }, }), ], diff --git a/src/lib/routes/admin-api/metrics.ts b/src/lib/routes/admin-api/metrics.ts index e6d44d1868..be753f2f6e 100644 --- a/src/lib/routes/admin-api/metrics.ts +++ b/src/lib/routes/admin-api/metrics.ts @@ -9,7 +9,11 @@ import { createRequestSchema } from '../../openapi/util/create-request-schema'; import { createResponseSchema } from '../../openapi/util/create-response-schema'; import { ApplicationSchema } from '../../openapi/spec/application-schema'; import { ApplicationsSchema } from '../../openapi/spec/applications-schema'; -import { emptyResponse } from '../../openapi/util/standard-responses'; +import { + emptyResponse, + getStandardResponses, +} from '../../openapi/util/standard-responses'; +import { CreateApplicationSchema } from '../../openapi/spec/create-application-schema'; class MetricsController extends Controller { private logger: Logger; @@ -43,10 +47,15 @@ class MetricsController extends Controller { openApiService.validPath({ tags: ['Metrics'], operationId: 'createApplication', + summary: + 'Create an application to connect reported metrics', + description: + 'Is used to report usage as well which sdk the application uses', responses: { 202: emptyResponse, + ...getStandardResponses(400, 401, 403), }, - requestBody: createRequestSchema('applicationSchema'), + requestBody: createRequestSchema('createApplicationSchema'), }), ], }); @@ -60,8 +69,11 @@ class MetricsController extends Controller { openApiService.validPath({ tags: ['Metrics'], operationId: 'deleteApplication', + summary: 'Delete an application', + description: `Delete the application specified in the request URL. Returns 200 OK if the application was successfully deleted or if it didn't exist`, responses: { 200: emptyResponse, + ...getStandardResponses(401, 403), }, }), ], @@ -74,6 +86,9 @@ class MetricsController extends Controller { middleware: [ openApiService.validPath({ tags: ['Metrics'], + summary: 'Get all applications', + description: + 'Returns all applications registered with Unleash. Applications can be created via metrics reporting or manual creation', operationId: 'getApplications', responses: { 200: createResponseSchema('applicationsSchema'), @@ -90,8 +105,12 @@ class MetricsController extends Controller { openApiService.validPath({ tags: ['Metrics'], operationId: 'getApplication', + summary: 'Get application data', + description: + 'Returns data about the specified application (`appName`). The data contains information on the name of the application, sdkVersion (which sdk reported these metrics, typically `unleash-client-node:3.4.1` or `unleash-client-java:7.1.0`), as well as data about how to display this application in a list.', responses: { 200: createResponseSchema('applicationSchema'), + ...getStandardResponses(404), }, }), ], @@ -117,7 +136,7 @@ class MetricsController extends Controller { } async createApplication( - req: Request<{ appName: string }, unknown, ApplicationSchema>, + req: Request<{ appName: string }, unknown, CreateApplicationSchema>, res: Response, ): Promise { const input = { 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 aaadbaf4ec..9782790caf 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 @@ -703,31 +703,46 @@ The provider you choose for your addon dictates what properties the \`parameters "applicationSchema": { "additionalProperties": false, "properties": { - "announced": { - "type": "boolean", - }, "appName": { + "description": "Name of the application", + "example": "accounting", "type": "string", }, "color": { + "description": "The CSS color that is used to color the application's entry in the application list", + "example": "red", "type": "string", }, "description": { + "description": "Extra information added about the application reporting the metrics. Only present if added via the Unleash Admin interface", + "example": "Application for reporting page visits", "type": "string", }, "icon": { + "description": "An URL to an icon file to be used for the applications's entry in the application list", + "example": "https://github.com/favicon.ico", "type": "string", }, "sdkVersion": { + "description": "Which SDK and version the application reporting uses. Typically represented as \`:\`", + "example": "unleash-client-java:8.0.0", "type": "string", }, "strategies": { + "description": "Which [strategies](https://docs.getunleash.io/topics/the-anatomy-of-unleash#activation-strategies) the application has loaded. Useful when trying to figure out if your [custom strategy](https://docs.getunleash.io/reference/custom-activation-strategies) has been loaded in the SDK", + "example": [ + "standard", + "gradualRollout", + "mySpecialCustomStrategy", + ], "items": { "type": "string", }, "type": "array", }, "url": { + "description": "A link to reference the application reporting the metrics. Could for instance be a GitHub link to the repository of the application", + "example": "https://github.com/Unleash/unleash-client-proxy-js", "type": "string", }, }, @@ -737,8 +752,10 @@ The provider you choose for your addon dictates what properties the \`parameters "type": "object", }, "applicationsSchema": { + "additionalProperties": false, "properties": { "applications": { + "description": "Contains a list of applications that have connected via an SDK", "items": { "$ref": "#/components/schemas/applicationSchema", }, @@ -783,12 +800,14 @@ The provider you choose for your addon dictates what properties the \`parameters "description": "A batch of metrics accumulated by Edge (or other compatible applications). Includes both application registrations as well usage metrics from clients", "properties": { "applications": { + "description": "A list of applications registered by an Unleash SDK", "items": { "$ref": "#/components/schemas/bulkRegistrationSchema", }, "type": "array", }, "metrics": { + "description": "a list of client usage metrics registered by downstream providers. (Typically Unleash Edge)", "items": { "$ref": "#/components/schemas/clientMetricsEnvSchema", }, @@ -1075,7 +1094,8 @@ The provider you choose for your addon dictates what properties the \`parameters "no": { "description": "How many times the toggle evaluated to false", "example": 50, - "type": "number", + "minimum": 0, + "type": "integer", }, "timestamp": { "$ref": "#/components/schemas/dateSchema", @@ -1098,7 +1118,8 @@ The provider you choose for your addon dictates what properties the \`parameters "yes": { "description": "How many times the toggle evaluated to true", "example": 974, - "type": "number", + "minimum": 0, + "type": "integer", }, }, "required": [ @@ -1109,22 +1130,32 @@ The provider you choose for your addon dictates what properties the \`parameters "type": "object", }, "clientMetricsSchema": { + "description": "Client usage metrics, accumulated in buckets of hour by hour by default", "properties": { "appName": { + "description": "The name of the application that is evaluating toggles", + "example": "insurance-selector", "type": "string", }, "bucket": { + "description": "Holds all metrics gathered over a window of time. Typically 1 hour wide", "properties": { "start": { "$ref": "#/components/schemas/dateSchema", + "description": "The start of the time window these metrics are valid for. The window is usually 1 hour wide", + "example": "1926-05-08T12:00:00.000Z", }, "stop": { "$ref": "#/components/schemas/dateSchema", + "description": "The end of the time window these metrics are valid for. The window is 1 hour wide", + "example": "1926-05-08T13:00:00.000Z", }, "toggles": { "additionalProperties": { "properties": { "no": { + "description": "How many times the toggle evaluated to false", + "example": 50, "minimum": 0, "type": "integer", }, @@ -1133,15 +1164,24 @@ The provider you choose for your addon dictates what properties the \`parameters "minimum": 0, "type": "integer", }, + "description": "How many times each variant was returned", + "example": { + "variantA": 15, + "variantB": 25, + "variantC": 5, + }, "type": "object", }, "yes": { + "description": "How many times the toggle evaluated to true", + "example": 974, "minimum": 0, - "type": "integer", + "type": "number", }, }, "type": "object", }, + "description": "an object containing feature names with yes/no plus variant usage", "example": { "myCoolToggle": { "no": 42, @@ -1168,9 +1208,13 @@ The provider you choose for your addon dictates what properties the \`parameters "type": "object", }, "environment": { + "description": "Which environment the application is running in", + "example": "development", "type": "string", }, "instanceId": { + "description": "A [(somewhat) unique identifier](https://docs.getunleash.io/reference/sdks/node#advanced-usage) for the application", + "example": "application-name-dacb1234", "type": "string", }, }, @@ -1332,6 +1376,53 @@ The provider you choose for your addon dictates what properties the \`parameters ], "type": "object", }, + "createApplicationSchema": { + "additionalProperties": true, + "description": "Reported application information from Unleash SDKs", + "properties": { + "appName": { + "description": "Name of the application", + "example": "accounting", + "type": "string", + }, + "color": { + "description": "Css color to be used to color the application's entry in the application list", + "example": "red", + "type": "string", + }, + "icon": { + "description": "An URL to an icon file to be used for the applications's entry in the application list", + "example": "https://github.com/favicon.ico", + "type": "string", + }, + "sdkVersion": { + "description": "Which SDK and version the application reporting uses. Typically represented as \`:\`", + "example": "unleash-client-java:8.0.0", + "type": "string", + }, + "strategies": { + "description": "Which [strategies](https://docs.getunleash.io/topics/the-anatomy-of-unleash#activation-strategies) the application has loaded. Useful when trying to figure out if your [custom strategy](https://docs.getunleash.io/reference/custom-activation-strategies) has been loaded in the SDK", + "example": [ + "standard", + "gradualRollout", + "mySpecialCustomStrategy", + ], + "items": { + "type": "string", + }, + "type": "array", + }, + "url": { + "description": "A link to reference the application reporting the metrics. Could for instance be a GitHub link to the repository of the application", + "example": "https://github.com/Unleash/unleash-client-proxy-js", + "type": "string", + }, + }, + "required": [ + "appName", + ], + "type": "object", + }, "createFeatureSchema": { "properties": { "description": { @@ -1849,25 +1940,39 @@ The provider you choose for your addon dictates what properties the \`parameters }, "featureEnvironmentMetricsSchema": { "additionalProperties": false, + "description": "How many times \`feautreName\` was evaluated to \`true\` (yes) and \`false\` (no) for \`appName\` in \`environmnet\`", "properties": { "appName": { + "description": "The name of the application the SDK is being used in", + "example": "accounting", "type": "string", }, "environment": { + "description": "Which environment the SDK is being used in", + "example": "development", "type": "string", }, "featureName": { + "description": "The name of the feature", + "example": "my.special.feature", "type": "string", }, "no": { - "type": "number", + "description": "How many times the toggle evaluated to false", + "example": 50, + "minimum": 0, + "type": "integer", }, "timestamp": { - "format": "date-time", - "type": "string", + "$ref": "#/components/schemas/dateSchema", + "description": "The start of the time window these metrics are valid for. The window is usually 1 hour wide", + "example": "1926-05-08T12:00:00.000Z", }, "yes": { - "type": "number", + "description": "How many times the toggle evaluated to true", + "example": 974, + "minimum": 0, + "type": "integer", }, }, "required": [ @@ -1960,18 +2065,24 @@ The provider you choose for your addon dictates what properties the \`parameters }, "featureMetricsSchema": { "additionalProperties": false, + "description": "A batch of feature metrics", "properties": { "data": { + "description": "Metrics gathered per environment", "items": { "$ref": "#/components/schemas/featureEnvironmentMetricsSchema", }, "type": "array", }, "maturity": { + "description": "The maturity level of this API (alpha, beta, stable, deprecated)", + "example": "stable", "type": "string", }, "version": { - "type": "number", + "description": "The version of this schema", + "minimum": 1, + "type": "integer", }, }, "required": [ @@ -2245,27 +2356,41 @@ The provider you choose for your addon dictates what properties the \`parameters }, "featureUsageSchema": { "additionalProperties": false, + "description": "How many applications have seen this feature toggle, as well as how this feature was evaluated the last hour", "properties": { "featureName": { + "description": "The name of the feature", + "example": "my.special.feature", "type": "string", }, "lastHourUsage": { + "description": "Last hour statistics. Accumulated per feature per environment. Contains counts for evaluations to true (yes) and to false (no)", "items": { "$ref": "#/components/schemas/featureEnvironmentMetricsSchema", }, "type": "array", }, "maturity": { + "description": "The maturity level of this API (alpha, beta, stable, deprecated)", + "example": "stable", "type": "string", }, "seenApplications": { + "description": "A list of applications seen using this feature", + "example": [ + "accounting", + "billing", + "booking", + ], "items": { "type": "string", }, "type": "array", }, "version": { - "type": "number", + "description": "The version of this schema", + "minimum": 1, + "type": "integer", }, }, "required": [ @@ -5913,6 +6038,7 @@ Note: passing \`null\` as a value for the description property will set it to an }, "/api/admin/client-metrics/features/{name}": { "get": { + "description": "Separate counts for yes (enabled), no (disabled), as well as how many times each variant was selected during the last hour", "operationId": "getFeatureUsageSummary", "parameters": [ { @@ -5935,7 +6061,89 @@ Note: passing \`null\` as a value for the description property will set it to an }, "description": "featureUsageSchema", }, + "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\`.", + }, + "403": { + "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 need the "UPDATE_ADDON" permission to perform this action in the "development" environment.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NoAccessError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "User credentials are valid but does not have enough privileges to execute this operation", + }, + "404": { + "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": "Could not find the addon with ID "12345".", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NotFoundError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "The requested resource was not found.", + }, }, + "summary": "Last hour of usage and a list of applications that have reported seeing this feature toggle", "tags": [ "Metrics", ], @@ -5965,7 +6173,89 @@ Note: passing \`null\` as a value for the description property will set it to an }, "description": "featureMetricsSchema", }, + "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\`.", + }, + "403": { + "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 need the "UPDATE_ADDON" permission to perform this action in the "development" environment.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NoAccessError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "User credentials are valid but does not have enough privileges to execute this operation", + }, + "404": { + "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": "Could not find the addon with ID "12345".", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NotFoundError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "The requested resource was not found.", + }, }, + "summary": "Feature usage metrics for the last 48 hours, grouped by hour", "tags": [ "Metrics", ], @@ -8202,6 +8492,7 @@ If the provided project does not exist, the list of events will be empty.", }, "/api/admin/metrics/applications": { "get": { + "description": "Returns all applications registered with Unleash. Applications can be created via metrics reporting or manual creation", "operationId": "getApplications", "responses": { "200": { @@ -8215,6 +8506,7 @@ If the provided project does not exist, the list of events will be empty.", "description": "applicationsSchema", }, }, + "summary": "Get all applications", "tags": [ "Metrics", ], @@ -8222,6 +8514,7 @@ If the provided project does not exist, the list of events will be empty.", }, "/api/admin/metrics/applications/{appName}": { "delete": { + "description": "Delete the application specified in the request URL. Returns 200 OK if the application was successfully deleted or if it didn't exist", "operationId": "deleteApplication", "parameters": [ { @@ -8237,12 +8530,68 @@ If the provided project does not exist, the list of events will be empty.", "200": { "description": "This response has no body.", }, + "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\`.", + }, + "403": { + "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 need the "UPDATE_ADDON" permission to perform this action in the "development" environment.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NoAccessError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "User credentials are valid but does not have enough privileges to execute this operation", + }, }, + "summary": "Delete an application", "tags": [ "Metrics", ], }, "get": { + "description": "Returns data about the specified application (\`appName\`). The data contains information on the name of the application, sdkVersion (which sdk reported these metrics, typically \`unleash-client-node:3.4.1\` or \`unleash-client-java:7.1.0\`), as well as data about how to display this application in a list.", "operationId": "getApplication", "parameters": [ { @@ -8265,12 +8614,41 @@ If the provided project does not exist, the list of events will be empty.", }, "description": "applicationSchema", }, + "404": { + "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": "Could not find the addon with ID "12345".", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NotFoundError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "The requested resource was not found.", + }, }, + "summary": "Get application data", "tags": [ "Metrics", ], }, "post": { + "description": "Is used to report usage as well which sdk the application uses", "operationId": "createApplication", "parameters": [ { @@ -8286,18 +8664,100 @@ If the provided project does not exist, the list of events will be empty.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/applicationSchema", + "$ref": "#/components/schemas/createApplicationSchema", }, }, }, - "description": "applicationSchema", + "description": "createApplicationSchema", "required": true, }, "responses": { "202": { "description": "This response has no body.", }, + "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\`.", + }, + "403": { + "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 need the "UPDATE_ADDON" permission to perform this action in the "development" environment.", + "type": "string", + }, + "name": { + "description": "The name of the error kind", + "example": "NoAccessError", + "type": "string", + }, + }, + "type": "object", + }, + }, + }, + "description": "User credentials are valid but does not have enough privileges to execute this operation", + }, }, + "summary": "Create an application to connect reported metrics", "tags": [ "Metrics", ],