mirror of
https://github.com/Unleash/unleash.git
synced 2025-08-04 13:48:56 +02:00
task: add OpenApi spec to metrics route (#1725)
* task: add OpenApi spec to metrics route
This commit is contained in:
parent
28251af39e
commit
32399291e0
@ -49,12 +49,16 @@ import { validateTagTypeSchema } from './spec/validate-tag-type-schema';
|
|||||||
import { variantSchema } from './spec/variant-schema';
|
import { variantSchema } from './spec/variant-schema';
|
||||||
import { variantsSchema } from './spec/variants-schema';
|
import { variantsSchema } from './spec/variants-schema';
|
||||||
import { versionSchema } from './spec/version-schema';
|
import { versionSchema } from './spec/version-schema';
|
||||||
|
import { applicationSchema } from './spec/application-schema';
|
||||||
|
import { applicationsSchema } from './spec/applications-schema';
|
||||||
import { tagWithVersionSchema } from './spec/tag-with-version-schema';
|
import { tagWithVersionSchema } from './spec/tag-with-version-schema';
|
||||||
|
|
||||||
// All schemas in `openapi/spec` should be listed here.
|
// All schemas in `openapi/spec` should be listed here.
|
||||||
export const schemas = {
|
export const schemas = {
|
||||||
apiTokenSchema,
|
apiTokenSchema,
|
||||||
apiTokensSchema,
|
apiTokensSchema,
|
||||||
|
applicationSchema,
|
||||||
|
applicationsSchema,
|
||||||
cloneFeatureSchema,
|
cloneFeatureSchema,
|
||||||
constraintSchema,
|
constraintSchema,
|
||||||
contextFieldSchema,
|
contextFieldSchema,
|
||||||
|
40
src/lib/openapi/spec/application-schema.ts
Normal file
40
src/lib/openapi/spec/application-schema.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { FromSchema } from 'json-schema-to-ts';
|
||||||
|
|
||||||
|
export const applicationSchema = {
|
||||||
|
$id: '#/components/schemas/applicationSchema',
|
||||||
|
type: 'object',
|
||||||
|
additionalProperties: false,
|
||||||
|
required: ['appName'],
|
||||||
|
properties: {
|
||||||
|
appName: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
sdkVersion: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
strategies: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
announced: {
|
||||||
|
type: 'boolean',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type ApplicationSchema = FromSchema<typeof applicationSchema>;
|
22
src/lib/openapi/spec/applications-schema.ts
Normal file
22
src/lib/openapi/spec/applications-schema.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { applicationSchema } from './application-schema';
|
||||||
|
import { FromSchema } from 'json-schema-to-ts';
|
||||||
|
|
||||||
|
export const applicationsSchema = {
|
||||||
|
$id: '#/components/schemas/applicationsSchema',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
applications: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
$ref: '#/components/schemas/applicationSchema',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
schemas: {
|
||||||
|
applicationSchema,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type ApplicationsSchema = FromSchema<typeof applicationsSchema>;
|
@ -84,7 +84,7 @@ test('should store application', () => {
|
|||||||
.expect(202);
|
.expect(202);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should store application details wihtout strategies', () => {
|
test('should store application details without strategies', () => {
|
||||||
expect.assertions(0);
|
expect.assertions(0);
|
||||||
const appName = '123!23';
|
const appName = '123!23';
|
||||||
|
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import Controller from '../controller';
|
import Controller from '../controller';
|
||||||
import { UPDATE_APPLICATION } from '../../types/permissions';
|
import { NONE, UPDATE_APPLICATION } from '../../types/permissions';
|
||||||
import { IUnleashConfig } from '../../types/option';
|
import { IUnleashConfig } from '../../types/option';
|
||||||
import { IUnleashServices } from '../../types/services';
|
import { IUnleashServices } from '../../types/services';
|
||||||
import { Logger } from '../../logger';
|
import { Logger } from '../../logger';
|
||||||
import ClientInstanceService from '../../services/client-metrics/instance-service';
|
import ClientInstanceService from '../../services/client-metrics/instance-service';
|
||||||
|
import { emptyResponse } from '../../openapi/spec/empty-response';
|
||||||
|
import { createRequestSchema, createResponseSchema } from '../../openapi';
|
||||||
|
import { ApplicationSchema } from '../../openapi/spec/application-schema';
|
||||||
|
import { ApplicationsSchema } from '../../openapi/spec/applications-schema';
|
||||||
|
|
||||||
class MetricsController extends Controller {
|
class MetricsController extends Controller {
|
||||||
private logger: Logger;
|
private logger: Logger;
|
||||||
@ -15,7 +19,8 @@ class MetricsController extends Controller {
|
|||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
{
|
{
|
||||||
clientInstanceService,
|
clientInstanceService,
|
||||||
}: Pick<IUnleashServices, 'clientInstanceService'>,
|
openApiService,
|
||||||
|
}: Pick<IUnleashServices, 'clientInstanceService' | 'openApiService'>,
|
||||||
) {
|
) {
|
||||||
super(config);
|
super(config);
|
||||||
this.logger = config.getLogger('/admin-api/metrics.ts');
|
this.logger = config.getLogger('/admin-api/metrics.ts');
|
||||||
@ -28,19 +33,68 @@ class MetricsController extends Controller {
|
|||||||
this.get('/feature-toggles', this.deprecated);
|
this.get('/feature-toggles', this.deprecated);
|
||||||
this.get('/feature-toggles/:name', this.deprecated);
|
this.get('/feature-toggles/:name', this.deprecated);
|
||||||
|
|
||||||
// in use
|
this.route({
|
||||||
this.post(
|
method: 'post',
|
||||||
'/applications/:appName',
|
path: '/applications/:appName',
|
||||||
this.createApplication,
|
handler: this.createApplication,
|
||||||
UPDATE_APPLICATION,
|
permission: UPDATE_APPLICATION,
|
||||||
);
|
middleware: [
|
||||||
this.delete(
|
openApiService.validPath({
|
||||||
'/applications/:appName',
|
tags: ['admin'],
|
||||||
this.deleteApplication,
|
operationId: 'createApplication',
|
||||||
UPDATE_APPLICATION,
|
responses: {
|
||||||
);
|
202: emptyResponse,
|
||||||
this.get('/applications/', this.getApplications);
|
},
|
||||||
this.get('/applications/:appName', this.getApplication);
|
requestBody: createRequestSchema('applicationSchema'),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
this.route({
|
||||||
|
method: 'delete',
|
||||||
|
path: '/applications/:appName',
|
||||||
|
handler: this.deleteApplication,
|
||||||
|
permission: UPDATE_APPLICATION,
|
||||||
|
acceptAnyContentType: true,
|
||||||
|
middleware: [
|
||||||
|
openApiService.validPath({
|
||||||
|
tags: ['admin'],
|
||||||
|
operationId: 'deleteApplication',
|
||||||
|
responses: {
|
||||||
|
200: emptyResponse,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
this.route({
|
||||||
|
method: 'get',
|
||||||
|
path: '/applications',
|
||||||
|
handler: this.getApplications,
|
||||||
|
permission: NONE,
|
||||||
|
middleware: [
|
||||||
|
openApiService.validPath({
|
||||||
|
tags: ['admin'],
|
||||||
|
operationId: 'getApplications',
|
||||||
|
responses: {
|
||||||
|
200: createResponseSchema('applicationsSchema'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
this.route({
|
||||||
|
method: 'get',
|
||||||
|
path: '/applications/:appName',
|
||||||
|
handler: this.getApplication,
|
||||||
|
permission: NONE,
|
||||||
|
middleware: [
|
||||||
|
openApiService.validPath({
|
||||||
|
tags: ['admin'],
|
||||||
|
operationId: 'getApplication',
|
||||||
|
responses: {
|
||||||
|
200: createResponseSchema('applicationSchema'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async deprecated(req: Request, res: Response): Promise<void> {
|
async deprecated(req: Request, res: Response): Promise<void> {
|
||||||
@ -51,20 +105,32 @@ class MetricsController extends Controller {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteApplication(req: Request, res: Response): Promise<void> {
|
async deleteApplication(
|
||||||
|
req: Request<{ appName: string }>,
|
||||||
|
res: Response,
|
||||||
|
): Promise<void> {
|
||||||
const { appName } = req.params;
|
const { appName } = req.params;
|
||||||
|
|
||||||
await this.clientInstanceService.deleteApplication(appName);
|
await this.clientInstanceService.deleteApplication(appName);
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
}
|
}
|
||||||
|
|
||||||
async createApplication(req: Request, res: Response): Promise<void> {
|
async createApplication(
|
||||||
const input = { ...req.body, appName: req.params.appName };
|
req: Request<{ appName: string }, unknown, ApplicationSchema>,
|
||||||
|
res: Response,
|
||||||
|
): Promise<void> {
|
||||||
|
const input = {
|
||||||
|
...req.body,
|
||||||
|
appName: req.params.appName,
|
||||||
|
};
|
||||||
await this.clientInstanceService.createApplication(input);
|
await this.clientInstanceService.createApplication(input);
|
||||||
res.status(202).end();
|
res.status(202).end();
|
||||||
}
|
}
|
||||||
|
|
||||||
async getApplications(req: Request, res: Response): Promise<void> {
|
async getApplications(
|
||||||
|
req: Request,
|
||||||
|
res: Response<ApplicationsSchema>,
|
||||||
|
): Promise<void> {
|
||||||
const query = req.query.strategyName
|
const query = req.query.strategyName
|
||||||
? { strategyName: req.query.strategyName as string }
|
? { strategyName: req.query.strategyName as string }
|
||||||
: {};
|
: {};
|
||||||
@ -74,7 +140,10 @@ class MetricsController extends Controller {
|
|||||||
res.json({ applications });
|
res.json({ applications });
|
||||||
}
|
}
|
||||||
|
|
||||||
async getApplication(req: Request, res: Response): Promise<void> {
|
async getApplication(
|
||||||
|
req: Request,
|
||||||
|
res: Response<ApplicationSchema>,
|
||||||
|
): Promise<void> {
|
||||||
const { appName } = req.params;
|
const { appName } = req.params;
|
||||||
|
|
||||||
const appDetails = await this.clientInstanceService.getApplication(
|
const appDetails = await this.clientInstanceService.getApplication(
|
||||||
|
@ -22,8 +22,8 @@ export interface IApplication {
|
|||||||
url?: string;
|
url?: string;
|
||||||
color?: string;
|
color?: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
createdAt: Date;
|
createdAt?: Date;
|
||||||
instances?: IClientInstance[];
|
instances?: IClientInstance[];
|
||||||
seenToggles: Record<string, any>;
|
seenToggles?: Record<string, any>;
|
||||||
links: Record<string, string>;
|
links?: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
@ -113,6 +113,53 @@ Object {
|
|||||||
],
|
],
|
||||||
"type": "object",
|
"type": "object",
|
||||||
},
|
},
|
||||||
|
"applicationSchema": Object {
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": Object {
|
||||||
|
"announced": Object {
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
|
"appName": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"color": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"description": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"icon": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"sdkVersion": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"strategies": Object {
|
||||||
|
"items": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
"url": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": Array [
|
||||||
|
"appName",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
},
|
||||||
|
"applicationsSchema": Object {
|
||||||
|
"properties": Object {
|
||||||
|
"applications": Object {
|
||||||
|
"items": Object {
|
||||||
|
"$ref": "#/components/schemas/applicationSchema",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"type": "object",
|
||||||
|
},
|
||||||
"cloneFeatureSchema": Object {
|
"cloneFeatureSchema": Object {
|
||||||
"properties": Object {
|
"properties": Object {
|
||||||
"name": Object {
|
"name": Object {
|
||||||
@ -2011,6 +2058,109 @@ Object {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"/api/admin/metrics/applications": Object {
|
||||||
|
"get": Object {
|
||||||
|
"operationId": "getApplications",
|
||||||
|
"responses": Object {
|
||||||
|
"200": Object {
|
||||||
|
"content": Object {
|
||||||
|
"application/json": Object {
|
||||||
|
"schema": Object {
|
||||||
|
"$ref": "#/components/schemas/applicationsSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"description": "applicationsSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tags": Array [
|
||||||
|
"admin",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"/api/admin/metrics/applications/{appName}": Object {
|
||||||
|
"delete": Object {
|
||||||
|
"operationId": "deleteApplication",
|
||||||
|
"parameters": Array [
|
||||||
|
Object {
|
||||||
|
"in": "path",
|
||||||
|
"name": "appName",
|
||||||
|
"required": true,
|
||||||
|
"schema": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"responses": Object {
|
||||||
|
"200": Object {
|
||||||
|
"description": "emptyResponse",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tags": Array [
|
||||||
|
"admin",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"get": Object {
|
||||||
|
"operationId": "getApplication",
|
||||||
|
"parameters": Array [
|
||||||
|
Object {
|
||||||
|
"in": "path",
|
||||||
|
"name": "appName",
|
||||||
|
"required": true,
|
||||||
|
"schema": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"responses": Object {
|
||||||
|
"200": Object {
|
||||||
|
"content": Object {
|
||||||
|
"application/json": Object {
|
||||||
|
"schema": Object {
|
||||||
|
"$ref": "#/components/schemas/applicationSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"description": "applicationSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tags": Array [
|
||||||
|
"admin",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"post": Object {
|
||||||
|
"operationId": "createApplication",
|
||||||
|
"parameters": Array [
|
||||||
|
Object {
|
||||||
|
"in": "path",
|
||||||
|
"name": "appName",
|
||||||
|
"required": true,
|
||||||
|
"schema": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"requestBody": Object {
|
||||||
|
"content": Object {
|
||||||
|
"application/json": Object {
|
||||||
|
"schema": Object {
|
||||||
|
"$ref": "#/components/schemas/applicationSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"description": "applicationSchema",
|
||||||
|
"required": true,
|
||||||
|
},
|
||||||
|
"responses": Object {
|
||||||
|
"202": Object {
|
||||||
|
"description": "emptyResponse",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tags": Array [
|
||||||
|
"admin",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
"/api/admin/projects": Object {
|
"/api/admin/projects": Object {
|
||||||
"get": Object {
|
"get": Object {
|
||||||
"operationId": "getProjects",
|
"operationId": "getProjects",
|
||||||
|
Loading…
Reference in New Issue
Block a user