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.16 - fixed namespaces in http module; moved metada…
Browse files Browse the repository at this point in the history
…ta-scanner, handler-creator to the core (#196)
  • Loading branch information
serhiisol authored Aug 30, 2023
1 parent 221d433 commit c49b967
Show file tree
Hide file tree
Showing 39 changed files with 235 additions and 260 deletions.
5 changes: 1 addition & 4 deletions server/integration/http/app-version/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { APP_VERSION, Module } from '@server';
import { Module } from '@server';

import { AppController } from './app.controller';

@Module({
controllers: [AppController],
providers: [
{ provide: APP_VERSION, useValue: 'app-version' },
],
})
export class AppModule { }
5 changes: 4 additions & 1 deletion server/integration/http/app-version/test/express.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Application, HttpStatus, Module } from '@server';
import { APP_VERSION, Application, HttpStatus, Module } from '@server';
import { ExpressAdapter } from '@server/express';
import { HttpModule } from '@server/http';
import * as request from 'supertest';
Expand All @@ -10,6 +10,9 @@ import { AppModule } from '../src/app.module';
HttpModule.create(ExpressAdapter),
AppModule,
],
providers: [
{ provide: APP_VERSION, useValue: 'app-version' },
],
})
class TestModule { }

Expand Down
5 changes: 4 additions & 1 deletion server/integration/http/app-version/test/fastify.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Application, HttpStatus, Module } from '@server';
import { APP_VERSION, Application, HttpStatus, Module } from '@server';
import { FastifyAdapter } from '@server/fastify';
import { HttpModule } from '@server/http';
import * as request from 'supertest';
Expand All @@ -10,6 +10,9 @@ import { AppModule } from '../src/app.module';
HttpModule.create(FastifyAdapter),
AppModule,
],
providers: [
{ provide: APP_VERSION, useValue: 'app-version' },
],
})
class TestModule { }

Expand Down
5 changes: 4 additions & 1 deletion server/integration/http/app-version/test/koa.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Application, HttpStatus, Module } from '@server';
import { APP_VERSION, Application, HttpStatus, Module } from '@server';
import { HttpModule } from '@server/http';
import { KoaAdapter } from '@server/koa';
import * as request from 'supertest';
Expand All @@ -10,6 +10,9 @@ import { AppModule } from '../src/app.module';
HttpModule.create(KoaAdapter),
AppModule,
],
providers: [
{ provide: APP_VERSION, useValue: 'app-version' },
],
})
class TestModule { }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Application, Module } from '@server';
import { Application, MetadataScanner, Module } from '@server';
import { ExpressAdapter } from '@server/express';
import { HttpModule } from '@server/http';
import { MetadataScanner } from '@server/http';

import { AppModule } from '../src/app.module';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Application, Module } from '@server';
import { Application, MetadataScanner, Module } from '@server';
import { FastifyAdapter } from '@server/fastify';
import { HttpModule } from '@server/http';
import { MetadataScanner } from '@server/http';

import { AppModule } from '../src/app.module';

Expand Down
3 changes: 1 addition & 2 deletions server/integration/http/metadata-scanner/test/koa.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Application, Module } from '@server';
import { Application, MetadataScanner, Module } from '@server';
import { HttpModule } from '@server/http';
import { MetadataScanner } from '@server/http';
import { KoaAdapter } from '@server/koa';

import { AppModule } from '../src/app.module';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Application, Module } from '@server';
import { APP_VERSION, Application, Module } from '@server';
import { SocketIoAdapter } from '@server/socket-io';
import { SocketsModule } from '@server/sockets';
import { connect, Socket } from 'socket.io-client';
Expand All @@ -10,6 +10,9 @@ import { AppModule } from '../src/app.module';
SocketsModule.create(SocketIoAdapter),
AppModule,
],
providers: [
{ provide: APP_VERSION, useValue: 'app-version' },
],
})
class TestModule { }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Application, Module } from '@server';
import { Application, MetadataScanner, Module } from '@server';
import { SocketIoAdapter } from '@server/socket-io';
import { MetadataScanner, SocketsModule } from '@server/sockets';
import { SocketsModule } from '@server/sockets';

import { AppModule } from '../src/app.module';

Expand Down
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.15"
"version": "1.0.0-beta.16"
}
2 changes: 1 addition & 1 deletion server/src/core/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ export class Application {
provide: ContainerManager,
useValue: containerManger,
},
...DEFAULT_PROVIDERS,
{
provide: ROOT_MODULE,
useValue: rootModule,
},
...DEFAULT_PROVIDERS,
]);

const moduleResolver = await container.get<ModuleResolver>(ModuleResolver);
Expand Down
21 changes: 17 additions & 4 deletions server/src/core/helpers/decorators.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
import { 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: object) {
export function paramDecoratorFactory(metadata: Partial<ParamMetadata>) {
return function (target: InstanceType<any>, methodName: string, index: number) {
const params = Reflect.getMetadata(PARAMS_METADATA, target.constructor) ?? [];
const params = Reflect.getMetadata(PARAMS_METADATA, target[methodName]) ?? [];
const argType = Reflect.getMetadata(PARAM_TYPE_METADATA, target, methodName)[index];
const argName = extractParamNames(target[methodName])[index];

params.push({ argName, argType, index, methodName, ...metadata });
params[index] = {
argName,
argType,
index,
methodName,
...metadata,
};

Reflect.defineMetadata(PARAMS_METADATA, params, target.constructor);
params
.filter((param: ParamMetadata) => param.paramType === metadata.paramType)
.forEach((param: ParamMetadata, index: number) => {
param.callIndex = index;
});

Reflect.defineMetadata(PARAMS_METADATA, params, target[methodName]);
};
}

Expand Down
51 changes: 51 additions & 0 deletions server/src/core/helpers/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Handler, ParamMetadata } from '../types';
import { toStandardType } from '../utils';
import { HttpStatus } from './constants';
import { Context } from './context';
import { ApiError } from './errors';

export abstract class HandlerCreator {
abstract getParam(param: ParamMetadata, args: unknown[]): Promise<unknown> | unknown;

message(message: unknown) {
if (message instanceof ApiError) {
return message.toObject();
}

if (message instanceof Error) {
return { message: message.message };
}

return message;
}

async params(metadata: ParamMetadata[], context: Context, args: unknown[]) {
const params$ = metadata.map(param => param.factory
? param.factory(context)
: this.getParam(param, args),
);
const params = await Promise.all(params$);

return params.map(paramFn => toStandardType(paramFn()));
}

async runHandler(handler: Handler) {
try {
return await handler();
} catch (error) {
return error;
}
}

status(message: unknown, status: number) {
if (message instanceof ApiError) {
return message.status;
}

if (message instanceof Error) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}

return status;
}
}
2 changes: 2 additions & 0 deletions server/src/core/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ export * from './container-manager';
export * from './context';
export * from './decorators';
export * from './errors';
export * from './handler';
export * from './metadata-scanner';
export * from './module-resolver';
export * from './param-validator';
export * from './pipe';
Expand Down
60 changes: 60 additions & 0 deletions server/src/core/helpers/metadata-scanner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Inject, Injectable, Optional } from '@decorators/di';

import { ClassConstructor, Metadata, MethodMetadata } from '../types';
import { addLeadingSlash, buildUrl } from '../utils';
import { APP_VERSION, ROOT_MODULE } from './constants';
import { Reflector } from './reflector';

@Injectable()
export class MetadataScanner {
constructor(
@Inject(APP_VERSION) @Optional() private appVersion = '',
@Inject(ROOT_MODULE) private rootModule: ClassConstructor,
private reflector: Reflector,
) { }

scan<M extends Metadata>() {
return this.scanModule(this.rootModule) as M[];
}

private scanModule(module: ClassConstructor, parentNamespaces = []) {
const { controllers, modules, namespace } = this.reflector.getModuleMetadata(module);
const namespaces = [...parentNamespaces, namespace];

const methods = controllers.map(controller => {
const metadata = this.reflector.getControllerMetadata(controller);

return metadata.methods.map((method: MethodMetadata) => {
const params = this.reflector.getParamsMetadata(controller, method.methodName);

const pipes = metadata.pipes
.filter(([, methodName]) => !methodName || methodName === method.methodName)
.map(([pipe]) => pipe);

const version = metadata.options?.ignoreVersion ? '' : this.appVersion;

const paths = [version, ...namespaces, metadata.url, method.url].filter(Boolean);
const url = addLeadingSlash(buildUrl(...paths));

return {
...method,
controller,
module,
params,
paths,
pipes,
url,
};
});
});

const nestedMethods = modules.map(module =>
this.scanModule(module, namespaces),
);

return [
...nestedMethods.flat(),
...methods.flat(),
];
}
}
7 changes: 5 additions & 2 deletions server/src/core/helpers/reflector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ export class Reflector {
getControllerMetadata(controller: ClassConstructor) {
const metadata = Reflect.getMetadata(CONTROLLER_METADATA, controller) as ControllerMetadata;
const methods = (Reflect.getMetadata(METHOD_METADATA, controller) ?? []) as MethodMetadata[];
const params = (Reflect.getMetadata(PARAMS_METADATA, controller) ?? []) as ParamMetadata[];
const pipes = (Reflect.getMetadata(PIPES_METADATA, controller) ?? []) as [ClassConstructor, string?][];

return { ...metadata, methods, params, pipes };
return { ...metadata, methods, pipes };
}

getMetadata(key: string, target: unknown, propertyKey?: string) {
Expand All @@ -21,4 +20,8 @@ export class Reflector {
getModuleMetadata(module: ClassConstructor) {
return Reflect.getMetadata(MODULE_METADATA, module) as ModuleMetadata;
}

getParamsMetadata(controller: ClassConstructor, methodName: string) {
return (Reflect.getMetadata(PARAMS_METADATA, controller.prototype[methodName]) ?? []) as ParamMetadata[];
}
}
6 changes: 5 additions & 1 deletion server/src/core/providers.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { Provider } from '@decorators/di';

import { ModuleResolver, ParamValidator, Pipeline, Reflector } from './helpers';
import { MetadataScanner, ModuleResolver, ParamValidator, Pipeline, Reflector } from './helpers';

export const DEFAULT_PROVIDERS = [
{
provide: Reflector,
useClass: Reflector,
},
{
provide: MetadataScanner,
useClass: MetadataScanner,
},
{
provide: ModuleResolver,
useClass: ModuleResolver,
Expand Down
11 changes: 11 additions & 0 deletions server/src/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,21 @@ export interface ParamMetadata {
// argument name defined in the function
argName?: string;
argType?: Handler | ClassConstructor;
// If decorator is used multiple times over the same method
callIndex: number;
factory?: (context: any) => Promise<any> | any;
index: number;
methodName: string;
paramName: string;
paramType: string;
paramValidator?: Validator;
}

export interface Metadata extends MethodMetadata {
controller: ClassConstructor;
module: ClassConstructor;
params: ParamMetadata[];
paths: string[];
pipes: ClassConstructor[];
url: string;
}
2 changes: 2 additions & 0 deletions server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'reflect-metadata';
export { Application } from './core/application';
export * from './core/decorators';
export { MetadataScanner } from './core/helpers';
export * from './core/helpers/constants/http-status';
export * from './core/helpers/constants/injectables';
export { Context } from './core/helpers/context';
export { createParamDecorator, Decorate } from './core/helpers/decorators';
export * from './core/helpers/errors';
export { PipeHandle, ProcessPipe } from './core/helpers/pipe';
Expand Down
4 changes: 3 additions & 1 deletion server/src/platforms/express/express-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ export class ExpressAdapter implements HttpApplicationAdapter {
}

close() {
this.server?.close();
if (this.server.listening) {
this.server.close();
}
}

getParam(type: ParameterType, name: string, req: express.Request, res: express.Response) {
Expand Down
4 changes: 4 additions & 0 deletions server/src/platforms/fastify/fastify-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export class FastifyAdapter implements HttpApplicationAdapter {

async close() {
await this.app.close();

if (this.server.listening) {
this.server.close();
}
}

getParam(type: ParameterType, name: string, req: Fastify.FastifyRequest, res: Fastify.FastifyReply) {
Expand Down
Loading

0 comments on commit c49b967

Please sign in to comment.