UNPKG

@decorators/server

Version:

node decorators - decorators for express library

335 lines (273 loc) 10.3 kB
![Node Decorators](https://github.com/serhiisol/node-decorators/blob/master/decorators.png?raw=true) # Http ## Installation Main dependencies ``` npm install @decorators/server @decorators/di --save ``` Adapter specific imports ``` npm install express body-parser --save ``` Or ``` npm install fastify @fastify/cookie @fastify/static @fastify/view --save ``` Or ``` npm install koa koa-bodyparser koa-mount koa-static koa-views --save ``` ## Example Fully working example can be found in [example](example) folder. ## Application In order to create an application, use `Application` class with app root module: ```typescript const app = await Application.create(AppModule, server?); ``` Application instance provides an `inject` method to retrieve instances of any provided objects: ```typescript const app = await Application.create(AppModule); const module = await app.inject<HttpModule>(HttpModule); module.use(json()); await module.listen(3000); ``` ## Modules * `HttpModule` - main module to start an application: ```typescript import { Module } from '@decorators/server'; import { HttpModule } from '@decorators/server/http'; import { ExpressAdapter } from '@decorators/server/express'; @Module({ modules: [ HttpModule.create(ExpressAdapter), ], }) export class AppModule { } ``` ## Adapters * `ExpressAdapter` - adapter for [express](https://github.com/expressjs/express) from `@decorators/server/express` * `FastifyAdapter` - adapter for [fastify](https://github.com/fastify/fastify) from `@decorators/server/fastify` * `KoaAdapter` - adapter for [koa](https://github.com/koajs/koa) from `@decorators/server/koa` Adapter can be instantiated with existing application (for example express application): ```ts HttpModule.create(new ExpressAdapter(app)); ``` ## Payload vaidation Package supports [class-validator](https://github.com/typestack/class-validator) and [class-transformer](https://github.com/typestack/class-transformer) packages, basic types validation is supported as well: ```typescript @Get(':id', 200) post(@Params() user: UserDto) { return user; } ``` ## Pipes Pipes allow to add additional "interceptors" before and after main route function. In order to implement a pipe import `ProcessPipe` interface and implement it: ```typescript import { PipeHandle, ProcessPipe } from '@decorators/server'; import { HttpContext } from '@decorators/server/http'; export class TransformPipe implements ProcessPipe { async run(context: HttpContext, handle: PipeHandle<string>) { const message = await handle(); return message.toLocaleString(); } } ``` Add `@Pipe` decorator to the method or to entire controller: ```typescript @Pipe(TransformPipe) process(@Body() body: object) ``` Pipes can be used both for controller and methods. ## Injectables Global server pipes can be applied by providing them via `GLOBAL_PIPE` injectable with `multi` (see [di](../di) package for details) flag: ```typescript import { GLOBAL_PIPE, Module } from '@decorators/server'; @Module({ providers: [ { provide: GLOBAL_PIPE, useClass: ServerPipe, multi: true, }, ], }) export class AppModule { } ``` ### App prefix To create global application prefix (aka version, namespace) use `APP_VERSION` injectable: ```typescript import { APP_VERSION, Module } from '@decorators/server'; @Module({ providers: [ { provide: APP_VERSION, useValue: 'v1', }, ], }) export class AppModule { } ``` ## Dependency injection This module supports dependency injection provided by `@decorators/di` package. For convinience, `@decorators/server` reexports all decorators from `@decorators/di` package. ## Decorators ### Class * `@Module(options: ModuleOptions)` - Defines a module (namespace) for DI providers, controllers etc. * `@Controller(url: string, options?: Record<string, unknown>)` - Registers controller for base url with optional options * `options?.ignoreVersion` - ignore global version prefix (provided `APP_VERSION`), can be useful to setup global handlers, such as 404 handling * `@Pipe(pipe: ClassConstructor<ProcessPipe>)` - Registers a pipe for a controller ### Method * `@Pipe(pipe: ClassConstructor<ProcessPipe>)` - Registers a pipe for a method #### @decorators/server/http * `@Delete(url: string, status?: number)` - Registers delete route * `@Get(url: string, status?: number)` - Registers get route * `@Head(url: string, status?: number)` - Registers head route * `@Options(url: string, status?: number)` - Registers options route * `@Patch(url: string, status?: number)` - Registers patch route * `@Post(url: string, status?: number)` - Registers post route * `@Put(url: string, status?: number)` - Registers put route * `@Render(template: string)` - Renders a template in the configured views folder ```typescript const app = await Application.create(AppModule); const module = await app.inject<HttpModule>(HttpModule); module.set('views', join(__dirname, '/views')); ``` ### Parameter * `@Body(paramName?: string, paramValidator?: Validator)` - Request body object or single body param * `@Cookies(paramName?: string, paramValidator?: Validator)` - Request cookies or single cookies param * `@Headers(paramName?: string, paramValidator?: Validator)` - Request headers object or single headers param * `@Params(paramName?: string, paramValidator?: Validator)` - Request params object or single param * `@Query(paramName?: string, paramValidator?: Validator)` - Request query object or single query param * `@Request(paramName?: string)` - Returns request object or any other object available in req object itself * `@Response(paramName?: string)` - Returns response object or any other object available in response object itself ## Custom Decorators Package exports two main helpers to create custom decorators: * `Decorate` - allows to create custom class or method decorators ```typescript import { Decorate } from '@decorators/server'; // ... @Decorate('hasAccess', 'granted') create() {} ``` To read custom metadata use `Reflector` injectable and its `getMeatada` method: ```typescript @Injectable() export class AccessPipe implements ProcessPipe { constructor(private reflector: Reflector) { } async run(context: HttpContext, handle: PipeHandle<string>) { const access = this.reflector.getMetadata('hasAccess', context.getHandler()); const req = context.getRequest<Request>(); if (access === req.query.access) { return handle(); } throw new ApiError('unauthorized'); } } ``` * `createParamDecorator(factory: (context: Context) => any)` - allows to create custom parameter decorators ```typescript import { createParamDecorator } from '@decorators/server'; function AccessParam() { return createParamDecorator((context: HttpContext) => { const req = context.getRequest<Request>(); return req.query.access; }); } // ... create(@AccessParam() access: string) {} ``` --- # Swagger Swagger decorators are available in ```typescript import { SwaggerModule } from '@decorators/server/swagger'; ``` To start with swagger decorators provide `SwaggerModule` in the `AppModule`, for example: ```typescript import { SwaggerModule } from '@decorators/server/swagger'; @Module({ modules: [ HttpModule.create(ExpressAdapter), SwaggerModule.forRoot({ description: 'Decorators Example App', title: '@decorators/server', }), ... ], }) export class AppModule { } ``` ## Decorators ### Method * `@ApiOperation(operation: OpenAPIV3_1.OperationObject)` - Registers an operation * `@ApiResponse(description: string, type?: ClassConstructor)` - Registers simple response for a method. This decorator uses status provided by the route decorator, e.g. `@Get(route, status)`. * `@ApiResponseSchema(responses: ApiResponses)` - Registers a response for a method. This method accepts more complex types of responses, if method returns more than one. * `@ApiBearerAuth()` - Defines a bearer authentication method for a route * `@ApiSecurity(security: OpenAPIV3_1.SecuritySchemeObject)` - Defines more complex authentication methods for a route. ### Property * `@ApiParameter(parammeter: { description?: string })` - Specifies a description for a property defined in the class-decorator based classes --- # Sockets ## Installation ``` npm install socket.io --save ``` ## Setup To start provide `SocketsModule` with one of the provided adapters ```typescript import { Module } from '@decorators/server'; import { SocketsModule } from '@decorators/server/sockets'; import { SocketIoAdapter } from '@decorators/server/socket-io'; @Module({ modules: [ SocketsModule.create(SocketIoAdapter), ], }) export class AppModule { } ``` Inject `SocketsModule` to start listeners ```ts const app = await Application.create(AppModule); const module = await app.inject<SocketsModule>(SocketsModule); await module.listen(); ``` Add a controller ```ts import { Controller } from '@server'; import { Connection, Disconnect, Event, Param } from '@server/sockets'; @Controller() export class EventsController { @Connection() connection() { } @Disconnect() disconnect() { } @Event('message') event(@Param() message: MessageType) { return message; } } ``` ## Errors If error occurres, system will send `error` event to the client with an error object. ## Adapters * `SocketIoAdapter` - adapter for [socket.io](https://socket.io) from `@decorators/server/socket-io` ## Payload vaidation Validation works similarly to http module see [validation](#payload-vaidation) section. ## Pipes Pipes work similarly to http module see [pipes](#pipes) section. ## Decorators ### Method * `@Connection()` - Registers `connection` event. * `@Disconnect()` - Registers `disconnect` event * `@Disconnecting()` - Registers `disconnecting` event * `@Event(event: string)` - Register custom event. Returned data from the handler will be sent through Ack. ### Parameter * `@Param(paramValidator?: Validator)` - Returns param sent via `emit`. Not available for `connection`, `disconnect` and `disconnecting` events. Multiple params can be used to receive all the params: ```ts message( @Param() message1: string, @Param() message2: string, ) { } ``` * `@Server()` - Returns server object * `@Socket()` - Returns socket object