express-mcs
v1.3.2
Published
Decorator based Module-Controller-Service system for Express
Downloads
10
Maintainers
Readme
express-mcs
Express-mcs is a decorator-based mini-framework that brings module-controller-service architecture to your express application.
Project is inspired by NestJS.
Numbers:
Installation
Npm
npm i express-mcs
Yarn
yarn add express-mcs
Quick guide
Create service
export class AppService {
public status() {
return { status: 'ok' };
}
}
Create controller
import { Controller, Get, Inject } from 'express-mcs';
@Controller('/api')
export class AppController {
constructor (
@Inject(AppService)
private readonly service: AppService,
) {}
@Get('/status')
public status() {
return this.service.status();
}
}
Create app module
import { Module } from 'express-mcs';
import { AppService } from './app.service';
import { AppController } from './app.controller';
@Module({
providers: [AppService],
controllers: [AppController],
})
export class AppModule {}
Initialize app module
// ...
initAppModule({
Module: AppModule,
app
});
// ...
app.listen(environment.PORT, () => {
// ...
});
Usage
Controllers
import { Controller, Get } from 'express-mcs';
@Controller('/api/v1/users')
export class UsersController {
@Get('/all')
public async find() {
return { status: 'ok', users: [] }
}
}
Controller decorator accepts root path.
Methods
You can use Get, Post, Put, Patch, Delete method decorators, which accept path as a parameter
Method params
Req
Injects request to controller method.
import { Request } from 'express';
import { Controller, Get, Req } from 'express-mcs';
@Controller('/api/v1/users')
export class UsersController {
@Get('/all')
public async find(@Req request: Request) {
...
}
}
Res
Injects response to controller method.
import { Response } from 'express';
import { Controller, Get, Res } from 'express-mcs';
@Controller('/api/v1/users')
export class UsersController {
@Get('/all')
public async find(@Res response: Response) {
res.status(401).send();
}
}
Headers
Injects request headers to controller method.
import { Response } from 'express';
import { Controller, Get, Headers } from 'express-mcs';
@Controller('/api/v1/users')
export class UsersController {
@Get('/all')
public async find(@Headers headers: unknown) {
...
}
}
Body
Injects request body to controller method.
import { Response } from 'express';
import { Controller, Post, Body } from 'express-mcs';
@Controller('/api/v1/users')
export class UsersController {
@Post('/create')
public async create(@Body() data: UserCreateDto) {
...
}
}
Query
Injects request query params to controller method.
import { Response } from 'express';
import { Controller, Get, Query } from 'express-mcs';
@Controller('/api/v1/users')
export class UsersController {
@Get('/find')
public async find(@Query() pagination: UserFindRequestQuery) {
...
}
}
Params
Injects request query params to controller method.
import { Response } from 'express';
import { Controller, Get, Params } from 'express-mcs';
@Controller('/api/v1/users')
export class UsersController {
@Get('/:id')
public async findOne(@Params() {id}: UserFindOneRequestParams) {
...
}
}
Data validation
Create validation func
import { validate } from 'class-validator';
import { Response } from 'express';
export async function getValidatedData(data: any, res: Response): Promise<unknown> {
const errors = await validate(data);
if (!errors.length) return data;
res.status(400).json(errors).send();
return undefined;
}
Pass validation function to module init
export const appModule = initAppModule({
Module: AppModule,
app,
getValidatedData,
});
Pass DTO class to Query/Body/Params
import { IsString } from 'class-validator';
import { Response } from 'express';
import { Controller, Post, Body } from 'express-mcs';
class UserCreateDto {
@IsString()
login!: string
}
@Controller('/api/v1/users')
export class UsersController {
@Post('/create')
public async create(@Body(UserCreateDto) data: UserCreateDto) {
...
}
}
Custom middleware
ApiKey auth middleware
import { getMiddleware, AuthorizationError } from 'express-mcs';
import { environment } from '../../environment';
export const AppApiGuard = getMiddleware(async (req) => {
if (req.headers.apikey !== environment.API_KEY) {
throw new AuthorizationError();
}
});
import { Controller, Post } from 'express-mcs';
import { AppApiGuard } from './api-key.strategy';
@Controller('/api/v1/data-sync')
export class DataSyncController {
@Post('/sync')
@AppApiGuard
public async syncItems() {
// ...
}
}
Handling errors
import { Response } from 'express';
import { HandleError, handleError as handleErrorDefault } from 'express-mcs';
import { CustomError } from './custom-error';
export const handleError: HandleError = async (res: Response, error: unknown) => {
if (error instanceof CustomError) {
res.status(400).json({ message: error.message });
} else {
await handleErrorDefault(res, error);
}
};
// ...
import { handleError } from './errors/handle-error';
// ...
export const appModule = initAppModule({
Module: AppModule,
app,
getValidatedData,
handleError,
});