mvc-middleware
Mvc middleware for express like .Net Mvc
Installation
npm i mvc-middleware
How to use
import { json } from 'body-parser';
import cors from 'cors';
import express from 'express';
import http from 'http';
import { MvcMiddleware } from 'mvc-middleware';
import path from 'path';
const controllersPath = path.join(__dirname, 'api');
const expressApp = express();
expressApp.use(cors()).use(json());
const mvcMiddleware = new MvcMiddleware(expressApp);
(async () => {
await mvcMiddleware.registerControllers(controllersPath);
http
.createServer(expressApp)
.listen(80, 'localhost');
})();
import { MvcController } from 'mvc-middleware';
@api('/api')
export default class UsersApi extends MvcController {
@GET
users() {
return this.ok(['user-1', 'user-2', 'user-3']);
}
}
import { MvcController } from 'mvc-middleware';
@api('/api')
export default class ArticlesApi extends MvcController {
@GET
async articles() {
const articles = await Promise.resolve(['article-1', 'article-2']);
return this.ok(articles);
}
}
Dependency injection
We recommend to use cheap-di package to handle your dependency injection:
import { container } from 'cheap-di';
import express from 'express';
const expressApp = express();
const mvcMiddleware = new MvcMiddleware(expressApp, container);
You may pass any custom DI resolver that implements the following contract:
type AbstractConstructor<T = any> = abstract new (...args: any[]) => T;
type Constructor<T = any> = new (...args: any[]) => T;
type Resolver = <TInstance>(type: Constructor<TInstance> | AbstractConstructor<TInstance>, ...args: any[]) => TInstance | undefined;
interface DependencyResolver {
resolve: Resolver;
}
Decorators
We have two sets of decorators: for stage 2 (legacy) and stage 3 proposals. You may choose one of them with imports:
import { api, GET, POST, PUT, PATCH, DELETE } from 'mvc-middleware/stage2';
import { api, GET, POST, PUT, PATCH, DELETE } from 'mvc-middleware/stage3';
decorator | description | variants of using |
---|
api | collect method names and types (get/post/...) and concat prefix to is urls | @api
@api('api')
@api('/api/domain') |
GET | marks method as handler for GET request, can change handled url | @GET
@GET('')
@GET('my-route')
@GET('/my-route') |
POST | marks method as handler for GET request, can change handled url | @POST
@POST('')
@POST('my-route')
@POST('/my-route') |
PUT | marks method as handler for PUT request, can change handled url | @PUT
@PUT('')
@PUT('my-route')
@PUT('/my-route') |
PATCH | marks method as handler for PATCH request, can change handled url | @PATCH
@PATCH('')
@PATCH('my-route')
@PATCH('/my-route') |
DELETE | marks method as handler for DELETE request, can change handled url | @DELETE
@DELETE('')
@DELETE('my-route')
@DELETE('/my-route') |
MvcController methods
Method name | Response status code | Response type | Arguments | Description |
---|
ok | 200 | text or json | model?: any | returns 200 status code with data |
created | 201 | text or json | model?: any | returns 201 status code with data |
accepted | 202 | text or json | model?: any | returns 202 status code with data |
noContent | 204 | - | - | returns 204 status code |
| | | | |
found | 302 | text | url: string | returns 302 status code |
permanentRedirect | 308 | text | url: string | returns 308 status code |
redirect | 300 - 308 | text | statusCode: number, url: string | returns redirection status code |
| | | | |
badRequest | 400 | text or json | model?: any | returns 400 status code with data |
unauthorized | 401 | text or json | model?: any | returns 401 status code with data |
forbid | 403 | - | model?: any | returns 403 status code |
notFound | 404 | text or json | model?: any | returns 404 status code with data |
conflict | 409 | text or json | model?: any | returns 409 status code with data |
| | | | |
serverError | 500 | text | message?: any | returns 500 status code with error message |
sendResponse | any http status code | text | model: any, statusCode?: number | returns status code with data. Default status code is 200 |
More examples
import { Request, Response } from 'express';
import { api, GET, POST } from 'mvc-middleware/stage2';
@api('/api/users')
export default class UsersController extends MvcController {
static users = [{
id: 1,
name: 'user 1',
}]
@GET('')
list() {
return this.ok(UsersController.users);
}
@GET(':userId')
getById(stringId: string) {
const userId = parseInt(stringId, 10);
const user = UsersController.users.find(user => user.id === userId);
return this.ok(user);
}
@POST('')
add({ name }: { name: string }) {
UsersController.users.push({
id: UsersController.users.length + 1,
name,
});
return this.ok('user is added');
}
}
If you want to get query params and body content, you have to connect another middleware that will handle requests before MvcMiddleware like below.
import express, { Router } from 'express';
import bodyParser from 'body-parser';
import { MvcMiddleware } from 'mvc-middleware';
const expressApp = express();
expressApp.use(bodyParser.json());
expressApp.use(bodyParser.urlencoded());
const mvcMiddleware = new MvcMiddleware(expressApp, container);