Skip to content
This repository has been archived by the owner on Aug 16, 2024. It is now read-only.

Commit

Permalink
feat(server): beta.17 - sockets swagger support (#197)
Browse files Browse the repository at this point in the history
  • Loading branch information
serhiisol authored Aug 30, 2023
1 parent c49b967 commit eca468a
Show file tree
Hide file tree
Showing 14 changed files with 131 additions and 23 deletions.
4 changes: 2 additions & 2 deletions server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,5 +148,5 @@
]
}
},
"version": "1.0.0-beta.16"
"version": "1.0.0-beta.17"
}
6 changes: 3 additions & 3 deletions server/src/core/helpers/decorators.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ParamMetadata } from '../types';
import { MethodMetadata, ParamMetadata } from '../types';
import { extractParamNames } from '../utils';
import { METHOD_METADATA, PARAM_TYPE_METADATA, PARAMS_METADATA, RETURN_TYPE_METADATA } from './constants';
import { Context } from './context';

export function paramDecoratorFactory(metadata: Partial<ParamMetadata>) {
export function paramDecoratorFactory(metadata: Partial<ParamMetadata> & { [key: string]: any; }) {
return function (target: InstanceType<any>, methodName: string, index: number) {
const params = Reflect.getMetadata(PARAMS_METADATA, target[methodName]) ?? [];
const argType = Reflect.getMetadata(PARAM_TYPE_METADATA, target, methodName)[index];
Expand All @@ -27,7 +27,7 @@ export function paramDecoratorFactory(metadata: Partial<ParamMetadata>) {
};
}

export function methodDecoratorFactory(metadata: object) {
export function methodDecoratorFactory(metadata: Partial<MethodMetadata> & { [key: string]: any; }) {
return (target: object, methodName: string, descriptor: TypedPropertyDescriptor<any>) => {
const methods = Reflect.getMetadata(METHOD_METADATA, target.constructor) ?? [];
const returnType = Reflect.getMetadata(RETURN_TYPE_METADATA, target, methodName);
Expand Down
1 change: 1 addition & 0 deletions server/src/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface ControllerMetadata {
export interface MethodMetadata {
methodName: string;
returnType: ClassConstructor;
source: string;
type: string;
url: string;
}
Expand Down
50 changes: 42 additions & 8 deletions server/src/platforms/http/decorators/route.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,66 @@
import { Decorate, methodDecoratorFactory } from '../../../core';
import { HttpMethodType, METHOD_TEMPLATE_METADATA } from '../helpers';
import { HttpMethodType, METHOD_TEMPLATE_METADATA, SOURCE_TYPE } from '../helpers';

export function Delete(url = '', status?: number) {
return methodDecoratorFactory({ status, type: HttpMethodType.DELETE, url });
return methodDecoratorFactory({
source: SOURCE_TYPE,
status,
type: HttpMethodType.DELETE,
url,
});
}

export function Get(url = '', status?: number) {
return methodDecoratorFactory({ status, type: HttpMethodType.GET, url });
return methodDecoratorFactory({
status,
type: HttpMethodType.GET,
url,
});
}

export function Head(url = '', status?: number) {
return methodDecoratorFactory({ status, type: HttpMethodType.HEAD, url });
return methodDecoratorFactory({
source: SOURCE_TYPE,
status,
type: HttpMethodType.HEAD,
url,
});
}

export function Options(url = '', status?: number) {
return methodDecoratorFactory({ status, type: HttpMethodType.OPTIONS, url });
return methodDecoratorFactory({
source: SOURCE_TYPE,
status,
type: HttpMethodType.OPTIONS,
url,
});
}

export function Patch(url = '', status?: number) {
return methodDecoratorFactory({ status, type: HttpMethodType.PATCH, url });
return methodDecoratorFactory({
source: SOURCE_TYPE,
status,
type: HttpMethodType.PATCH,
url,
});
}

export function Post(url = '', status?: number) {
return methodDecoratorFactory({ status, type: HttpMethodType.POST, url });
return methodDecoratorFactory({
source: SOURCE_TYPE,
status,
type: HttpMethodType.POST,
url,
});
}

export function Put(url = '', status?: number) {
return methodDecoratorFactory({ status, type: HttpMethodType.PUT, url });
return methodDecoratorFactory({
source: SOURCE_TYPE,
status,
type: HttpMethodType.PUT,
url,
});
}

export function Render(template: string) {
Expand Down
1 change: 1 addition & 0 deletions server/src/platforms/http/helpers/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './constants';
export * from './http-method-type';
export * from './injectables';
export * from './parameter-type';
export * from './source-type';
1 change: 1 addition & 0 deletions server/src/platforms/http/helpers/constants/source-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const SOURCE_TYPE = 'http';
2 changes: 1 addition & 1 deletion server/src/platforms/http/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './decorators';
export { HTTP_ADAPTER, HttpApplicationAdapter, HttpContext, ParameterType } from './helpers';
export { HTTP_ADAPTER, HttpApplicationAdapter, HttpContext, HttpMethodType, ParameterType, SOURCE_TYPE } from './helpers';
export * from './http.module';
export { AdapterRoute, RouteMetadata } from './types';
6 changes: 5 additions & 1 deletion server/src/platforms/sockets/decorators/events.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
import { methodDecoratorFactory } from '../../../core';
import { EventType } from '../helpers';
import { EventType, SOURCE_TYPE } from '../helpers';

export function Connection() {
return methodDecoratorFactory({
source: SOURCE_TYPE,
type: EventType.CONNECTION,
});
}

export function Disconnect() {
return methodDecoratorFactory({
source: SOURCE_TYPE,
type: EventType.DISCONNECT,
});
}

export function Disconnecting() {
return methodDecoratorFactory({
source: SOURCE_TYPE,
type: EventType.DISCONNECTING,
});
}

export function Event(event: string) {
return methodDecoratorFactory({
event,
source: SOURCE_TYPE,
type: EventType.EVENT,
});
}
1 change: 1 addition & 0 deletions server/src/platforms/sockets/helpers/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './event-type';
export * from './injectables';
export * from './parameter-type';
export * from './source-type';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const SOURCE_TYPE = 'sockets';
2 changes: 1 addition & 1 deletion server/src/platforms/sockets/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './decorators';
export { ParameterType, SOCKETS_ADAPTER, SocketsApplicationAdapter, SocketsContext } from './helpers';
export { ParameterType, SOCKETS_ADAPTER, SocketsApplicationAdapter, SocketsContext, SOURCE_TYPE } from './helpers';
export * from './sockets.module';
export { AdapterEvent, EventMetadata } from './types';
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ import { Inject, Injectable, Optional } from '@decorators/di';
import { OpenAPIV3_1 } from 'openapi-types';

import { APP_VERSION, ClassConstructor, Handler, MetadataScanner, Reflector } from '../../../../core';
import { ParameterType, RouteMetadata } from '../../../http';
import { HttpMethodType, ParameterType, RouteMetadata } from '../../../http';
import { SOURCE_TYPE as SOCKETS_SOURCE_TYPE } from '../../../sockets';
import { ApiResponse, SwaggerConfig } from '../../types';
import { METHOD_API_RESPONSE_METADATA, METHOD_API_RESPONSES_METADATA, METHOD_API_SECURITY_METADATA, PROPERTY_API_PARAMETER_METADATA, SWAGGER_CONFIG } from '../constants';
import { METHOD_API_OPERATION_METADATA, METHOD_API_RESPONSE_METADATA, METHOD_API_RESPONSES_METADATA, METHOD_API_SECURITY_METADATA, PROPERTY_API_PARAMETER_METADATA, SWAGGER_CONFIG } from '../constants';
import { getValidationMeta, isStandardType, pick, replaceUrlParameters, typeToContentType } from './utils';

export const DEFAULT_STATUS = 200;
export const DEFAULT_METHOD = HttpMethodType.POST;

@Injectable()
export class SwaggerDocument {
private paths = {};
Expand Down Expand Up @@ -53,6 +57,10 @@ export class SwaggerDocument {
METHOD_API_RESPONSES_METADATA,
route.controller.prototype[route.methodName],
);
const operationMeta = this.reflector.getMetadata(
METHOD_API_OPERATION_METADATA,
route.controller.prototype[route.methodName],
);

const ctrlMethod = `${route.controller.name}.${route.methodName}`;

Expand All @@ -79,19 +87,27 @@ export class SwaggerDocument {
};
}

const preResponses = { [route.status]: { type: route.returnType, ...simpleMeta }, ...detailedMeta };
const preResponses = {
[route.status || DEFAULT_STATUS]: { type: route.returnType, ...simpleMeta },
...detailedMeta,
};
const responses = Object.keys(preResponses).reduce((acc, status) => ({
...acc, [status]: this.toResponse(preResponses[status], route.methodName),
}), {});

const security = this.securitySchemas[ctrlMethod] ? [{ [ctrlMethod]: [] }] : [];

const tag = route.source === SOCKETS_SOURCE_TYPE
? `Sockets :: ${route.controller.name}`
: route.controller.name;

return {
...operationMeta,
parameters,
requestBody,
responses,
security,
tags: [route.controller.name],
tags: [tag],
} as OpenAPIV3_1.OperationObject;
}

Expand Down Expand Up @@ -165,11 +181,18 @@ export class SwaggerDocument {
this.securitySchemas[`${route.controller.name}.${route.methodName}`] = meta;
}

const url = replaceUrlParameters(route.url);
const rawUrl = replaceUrlParameters(route.url);
const url = route.source === SOCKETS_SOURCE_TYPE
? `${rawUrl} => ${route.type}` + (route['event'] ? ` => ${route['event']}` : '')
: rawUrl;

const methodType = route.source === SOCKETS_SOURCE_TYPE
? DEFAULT_METHOD
: route.type;

this.paths[url] = {
...(this.paths[url] ?? {}),
[route.type]: this.getPath(route),
[methodType]: this.getPath(route),
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,27 @@ function initializerScriptContent(jsonPath: string) {
],
layout: "StandaloneLayout"
});
onSwaggerUIReady(disableSocketsTryItOut);
};
function onSwaggerUIReady(fn) {
const interval = setInterval(() => {
if (document.getElementById('swagger-ui')) {
clearInterval(interval);
fn();
}
}, 100);
}
function disableSocketsTryItOut() {
const socketEvents = [...document.querySelectorAll('[data-tag^="sockets" i]')];
for (const el of socketEvents) {
el.parentElement.classList.add('server-swagger-sockets');
}
}
`;
}

Expand All @@ -90,6 +110,28 @@ function indexStyles(theme: SwaggerConfig['theme']) {

const styleOverrides = `
${styles}
.server-swagger-sockets .try-out {
display: none;
}
.server-swagger-sockets .opblock-summary-method {
overflow: hidden;
position: relative;
}
.server-swagger-sockets .opblock-summary-method::after {
align-items: center;
background-color: #a748cb;
bottom: 0;
content: 'SOCKETS';
display: flex;
justify-content: center;
left: 0;
position: absolute;
right: 0;
top: 0;
}
`;

if (theme === 'light') {
Expand Down

0 comments on commit eca468a

Please sign in to comment.