@decorators/server
Version:
node decorators - decorators for express library
335 lines (273 loc) • 10.3 kB
Markdown

# 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