3.0.0 • Published 4 months ago
mvc-middleware v3.0.0
mvc-middleware
Mvc middleware for express like .Net Mvc
Installation
npm i mvc-middleware
How to use
// src/index.ts
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';
// Path to folder where you have your controllers.
// Middleware will search controllers recursively.
// Each file with '.ts' extension and default export and
// typeof === 'function', decorated with '@api' will be
// assumed as controller class.
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');
})();
// src/api/UsersApi.ts
import { MvcController } from 'mvc-middleware';
@api('/api')
export default class UsersApi extends MvcController {
@GET // api/users
users() {
return this.ok(['user-1', 'user-2', 'user-3']);
}
}
// src/api/ArticlesApi.ts
import { MvcController } from 'mvc-middleware';
@api('/api')
export default class ArticlesApi extends MvcController {
@GET // articles
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 {
/** instantiate by class */
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
// src/api/UsersController.ts
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: /api/users
@GET('')
list() {
return this.ok(UsersController.users);
}
// GET: /api/users/:userId
@GET(':userId')
getById(stringId: string) {
const userId = parseInt(stringId, 10);
const user = UsersController.users.find(user => user.id === userId);
return this.ok(user);
}
// POST: /api/users
@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.
// src/index.ts
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);
// ...
3.0.0
4 months ago
3.0.0-rc.2
4 months ago
3.0.0-rc.1
4 months ago
3.0.0-alpha.2
4 months ago
3.0.0-alpha.1
5 months ago
2.0.0
1 year ago
1.1.4
3 years ago
1.1.3
3 years ago
1.1.2
3 years ago
1.1.1
4 years ago
1.1.0
4 years ago
1.0.2
4 years ago
1.0.1
4 years ago
1.0.0
4 years ago
0.1.2
4 years ago
0.1.1
4 years ago
0.1.0
4 years ago