inversify-express-utils
Advanced tools
Comparing version 5.0.0-beta.1 to 5.0.0
import { interfaces } from "./interfaces"; | ||
export declare class BaseHttpController { | ||
protected httpContext: interfaces.HttpContext; | ||
protected readonly httpContext: interfaces.HttpContext; | ||
} |
@@ -10,2 +10,3 @@ declare const TYPE: { | ||
controllerParameter: string; | ||
httpContext: string; | ||
}; | ||
@@ -12,0 +13,0 @@ export declare enum PARAMETER_TYPE { |
import { interfaces } from "./interfaces"; | ||
import { PARAMETER_TYPE } from "./constants"; | ||
export declare const httpContext: (target: any, targetKey: string, index?: number | undefined) => void; | ||
export declare const injectHttpContext: (target: any, targetKey: string, index?: number | undefined) => void; | ||
export declare function controller(path: string, ...middleware: interfaces.Middleware[]): (target: any) => void; | ||
@@ -5,0 +5,0 @@ export declare function all(path: string, ...middleware: interfaces.Middleware[]): interfaces.HandlerDecorator; |
import { InversifyExpressServer } from "./server"; | ||
import { controller, httpMethod, httpGet, httpPut, httpPost, httpPatch, httpHead, all, httpDelete, request, response, requestParam, queryParam, requestBody, requestHeaders, cookies, next, httpContext } from "./decorators"; | ||
import { controller, httpMethod, httpGet, httpPut, httpPost, httpPatch, httpHead, all, httpDelete, request, response, requestParam, queryParam, requestBody, requestHeaders, cookies, next, injectHttpContext } from "./decorators"; | ||
import { TYPE } from "./constants"; | ||
import { interfaces } from "./interfaces"; | ||
import { BaseHttpController } from "./base_http_controller"; | ||
import { BaseMiddleware } from "./base_middleware"; | ||
import { cleanUpMetadata } from "./utils"; | ||
export { cleanUpMetadata, interfaces, InversifyExpressServer, controller, httpMethod, httpGet, httpPut, httpPost, httpPatch, httpHead, all, httpDelete, TYPE, request, response, requestParam, queryParam, requestBody, requestHeaders, cookies, next, BaseHttpController, httpContext }; | ||
export { cleanUpMetadata, interfaces, InversifyExpressServer, controller, httpMethod, httpGet, httpPut, httpPost, httpPatch, httpHead, all, httpDelete, TYPE, request, response, requestParam, queryParam, requestBody, requestHeaders, cookies, next, BaseHttpController, injectHttpContext, BaseMiddleware }; |
@@ -49,3 +49,4 @@ /// <reference types="express" /> | ||
private handlerFactory(controllerName, key, parameterMetadata); | ||
private _getHttpContext(req, res, next); | ||
private _getHttpContext(req); | ||
private _createHttpContext(req, res, next); | ||
private _getCurrentUser(req, res, next); | ||
@@ -52,0 +53,0 @@ private extractParameters(req, res, next, params); |
@@ -11,3 +11,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
import { injectable } from "inversify"; | ||
import { httpContext } from "./decorators"; | ||
import { injectHttpContext } from "./decorators"; | ||
var BaseHttpController = /** @class */ (function () { | ||
@@ -17,3 +17,3 @@ function BaseHttpController() { | ||
__decorate([ | ||
httpContext, | ||
injectHttpContext, | ||
__metadata("design:type", Object) | ||
@@ -20,0 +20,0 @@ ], BaseHttpController.prototype, "httpContext", void 0); |
@@ -7,5 +7,6 @@ var TYPE = { | ||
var METADATA_KEY = { | ||
controller: "_controller", | ||
controllerMethod: "_controller-method", | ||
controllerParameter: "_controller-parameter" | ||
controller: "inversify-express-utils:controller", | ||
controllerMethod: "inversify-express-utils:controller-method", | ||
controllerParameter: "inversify-express-utils:controller-parameter", | ||
httpContext: "inversify-express-utils:httpcontext" | ||
}; | ||
@@ -12,0 +13,0 @@ export var PARAMETER_TYPE; |
import { inject, injectable, decorate } from "inversify"; | ||
import { TYPE, METADATA_KEY, PARAMETER_TYPE } from "./constants"; | ||
export var httpContext = inject(TYPE.HttpContext); | ||
export var injectHttpContext = inject(TYPE.HttpContext); | ||
export function controller(path) { | ||
@@ -83,3 +83,9 @@ var middleware = []; | ||
return function (target, key, value) { | ||
var metadata = { path: path, middleware: middleware, method: method, target: target, key: key }; | ||
var metadata = { | ||
key: key, | ||
method: method, | ||
middleware: middleware, | ||
path: path, | ||
target: target | ||
}; | ||
var metadataList = []; | ||
@@ -86,0 +92,0 @@ if (!Reflect.hasOwnMetadata(METADATA_KEY.controllerMethod, target.constructor)) { |
import { InversifyExpressServer } from "./server"; | ||
import { controller, httpMethod, httpGet, httpPut, httpPost, httpPatch, httpHead, all, httpDelete, request, response, requestParam, queryParam, requestBody, requestHeaders, cookies, next, httpContext } from "./decorators"; | ||
import { controller, httpMethod, httpGet, httpPut, httpPost, httpPatch, httpHead, all, httpDelete, request, response, requestParam, queryParam, requestBody, requestHeaders, cookies, next, injectHttpContext } from "./decorators"; | ||
import { TYPE } from "./constants"; | ||
import { BaseHttpController } from "./base_http_controller"; | ||
import { BaseMiddleware } from "./base_middleware"; | ||
import { cleanUpMetadata } from "./utils"; | ||
export { cleanUpMetadata, InversifyExpressServer, controller, httpMethod, httpGet, httpPut, httpPost, httpPatch, httpHead, all, httpDelete, TYPE, request, response, requestParam, queryParam, requestBody, requestHeaders, cookies, next, BaseHttpController, httpContext }; | ||
export { cleanUpMetadata, InversifyExpressServer, controller, httpMethod, httpGet, httpPut, httpPost, httpPatch, httpHead, all, httpDelete, TYPE, request, response, requestParam, queryParam, requestBody, requestHeaders, cookies, next, BaseHttpController, injectHttpContext, BaseMiddleware }; |
@@ -37,2 +37,3 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
import * as express from "express"; | ||
import { BaseMiddleware } from "./index"; | ||
import { TYPE, METADATA_KEY, DEFAULT_ROUTING_ROOT_PATH, PARAMETER_TYPE, DUPLICATED_CONTROLLER_NAME } from "./constants"; | ||
@@ -89,2 +90,22 @@ /** | ||
InversifyExpressServer.prototype.build = function () { | ||
var _this = this; | ||
var _self = this; | ||
// The very first middleware to be invoked | ||
// it creates a new httpContext and attaches it to the | ||
// current request as metadata using Reflect | ||
this._app.all("*", function (req, res, next) { | ||
(function () { return __awaiter(_this, void 0, void 0, function () { | ||
var httpContext; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, _self._createHttpContext(req, res, next)]; | ||
case 1: | ||
httpContext = _a.sent(); | ||
Reflect.defineMetadata(METADATA_KEY.httpContext, httpContext, req); | ||
next(); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); })(); | ||
}); | ||
// register server-level middleware before anything else | ||
@@ -144,6 +165,17 @@ if (this._configFn) { | ||
return middleware.map(function (middlewareItem) { | ||
try { | ||
return _this._container.get(middlewareItem); | ||
if (_this._container.isBound(middlewareItem)) { | ||
var m_1 = _this._container.get(middlewareItem); | ||
if (m_1 instanceof BaseMiddleware) { | ||
var _self_1 = _this; | ||
return function (req, res, next) { | ||
var httpContext = _self_1._getHttpContext(req); | ||
m_1.httpContext = httpContext; | ||
m_1.handler(req, res, next); | ||
}; | ||
} | ||
else { | ||
return m_1; | ||
} | ||
} | ||
catch (_) { | ||
else { | ||
return middlewareItem; | ||
@@ -158,21 +190,17 @@ } | ||
(function () { return __awaiter(_this, void 0, void 0, function () { | ||
var httpContext, childContainer, result, _a; | ||
var childContainer, httpContext, result, _a; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: return [4 /*yield*/, this._getHttpContext(req, res, next)]; | ||
case 1: | ||
httpContext = _b.sent(); | ||
childContainer = this._container.createChild(); | ||
childContainer.bind(TYPE.HttpContext) | ||
.toConstantValue(httpContext); | ||
result = (_a = childContainer.getNamed(TYPE.Controller, controllerName))[key].apply(_a, args); | ||
Promise.resolve(result) | ||
.then(function (value) { | ||
if (value && !res.headersSent) { | ||
res.send(value); | ||
} | ||
}) | ||
.catch(function (error) { return next(error); }); | ||
return [2 /*return*/]; | ||
} | ||
childContainer = this._container.createChild(); | ||
httpContext = this._getHttpContext(req); | ||
childContainer.bind(TYPE.HttpContext) | ||
.toConstantValue(httpContext); | ||
result = (_a = childContainer.getNamed(TYPE.Controller, controllerName))[key].apply(_a, args); | ||
Promise.resolve(result) | ||
.then(function (value) { | ||
if (value && !res.headersSent) { | ||
res.send(value); | ||
} | ||
}) | ||
.catch(function (error) { return next(error); }); | ||
return [2 /*return*/]; | ||
}); | ||
@@ -182,3 +210,7 @@ }); })(); | ||
}; | ||
InversifyExpressServer.prototype._getHttpContext = function (req, res, next) { | ||
InversifyExpressServer.prototype._getHttpContext = function (req) { | ||
var httpContext = Reflect.getOwnMetadata(METADATA_KEY.httpContext, req); | ||
return httpContext; | ||
}; | ||
InversifyExpressServer.prototype._createHttpContext = function (req, res, next) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
@@ -185,0 +217,0 @@ var principal, httpContext; |
@@ -18,3 +18,3 @@ "use strict"; | ||
__decorate([ | ||
decorators_1.httpContext, | ||
decorators_1.injectHttpContext, | ||
__metadata("design:type", Object) | ||
@@ -21,0 +21,0 @@ ], BaseHttpController.prototype, "httpContext", void 0); |
@@ -10,5 +10,6 @@ "use strict"; | ||
var METADATA_KEY = { | ||
controller: "_controller", | ||
controllerMethod: "_controller-method", | ||
controllerParameter: "_controller-parameter" | ||
controller: "inversify-express-utils:controller", | ||
controllerMethod: "inversify-express-utils:controller-method", | ||
controllerParameter: "inversify-express-utils:controller-parameter", | ||
httpContext: "inversify-express-utils:httpcontext" | ||
}; | ||
@@ -15,0 +16,0 @@ exports.METADATA_KEY = METADATA_KEY; |
@@ -5,3 +5,3 @@ "use strict"; | ||
var constants_1 = require("./constants"); | ||
exports.httpContext = inversify_1.inject(constants_1.TYPE.HttpContext); | ||
exports.injectHttpContext = inversify_1.inject(constants_1.TYPE.HttpContext); | ||
function controller(path) { | ||
@@ -94,3 +94,9 @@ var middleware = []; | ||
return function (target, key, value) { | ||
var metadata = { path: path, middleware: middleware, method: method, target: target, key: key }; | ||
var metadata = { | ||
key: key, | ||
method: method, | ||
middleware: middleware, | ||
path: path, | ||
target: target | ||
}; | ||
var metadataList = []; | ||
@@ -97,0 +103,0 @@ if (!Reflect.hasOwnMetadata(constants_1.METADATA_KEY.controllerMethod, target.constructor)) { |
@@ -23,3 +23,3 @@ "use strict"; | ||
exports.next = decorators_1.next; | ||
exports.httpContext = decorators_1.httpContext; | ||
exports.injectHttpContext = decorators_1.injectHttpContext; | ||
var constants_1 = require("./constants"); | ||
@@ -29,3 +29,5 @@ exports.TYPE = constants_1.TYPE; | ||
exports.BaseHttpController = base_http_controller_1.BaseHttpController; | ||
var base_middleware_1 = require("./base_middleware"); | ||
exports.BaseMiddleware = base_middleware_1.BaseMiddleware; | ||
var utils_1 = require("./utils"); | ||
exports.cleanUpMetadata = utils_1.cleanUpMetadata; |
@@ -39,2 +39,3 @@ "use strict"; | ||
var express = require("express"); | ||
var index_1 = require("./index"); | ||
var constants_1 = require("./constants"); | ||
@@ -91,2 +92,22 @@ /** | ||
InversifyExpressServer.prototype.build = function () { | ||
var _this = this; | ||
var _self = this; | ||
// The very first middleware to be invoked | ||
// it creates a new httpContext and attaches it to the | ||
// current request as metadata using Reflect | ||
this._app.all("*", function (req, res, next) { | ||
(function () { return __awaiter(_this, void 0, void 0, function () { | ||
var httpContext; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, _self._createHttpContext(req, res, next)]; | ||
case 1: | ||
httpContext = _a.sent(); | ||
Reflect.defineMetadata(constants_1.METADATA_KEY.httpContext, httpContext, req); | ||
next(); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); })(); | ||
}); | ||
// register server-level middleware before anything else | ||
@@ -146,6 +167,17 @@ if (this._configFn) { | ||
return middleware.map(function (middlewareItem) { | ||
try { | ||
return _this._container.get(middlewareItem); | ||
if (_this._container.isBound(middlewareItem)) { | ||
var m_1 = _this._container.get(middlewareItem); | ||
if (m_1 instanceof index_1.BaseMiddleware) { | ||
var _self_1 = _this; | ||
return function (req, res, next) { | ||
var httpContext = _self_1._getHttpContext(req); | ||
m_1.httpContext = httpContext; | ||
m_1.handler(req, res, next); | ||
}; | ||
} | ||
else { | ||
return m_1; | ||
} | ||
} | ||
catch (_) { | ||
else { | ||
return middlewareItem; | ||
@@ -160,21 +192,17 @@ } | ||
(function () { return __awaiter(_this, void 0, void 0, function () { | ||
var httpContext, childContainer, result, _a; | ||
var childContainer, httpContext, result, _a; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: return [4 /*yield*/, this._getHttpContext(req, res, next)]; | ||
case 1: | ||
httpContext = _b.sent(); | ||
childContainer = this._container.createChild(); | ||
childContainer.bind(constants_1.TYPE.HttpContext) | ||
.toConstantValue(httpContext); | ||
result = (_a = childContainer.getNamed(constants_1.TYPE.Controller, controllerName))[key].apply(_a, args); | ||
Promise.resolve(result) | ||
.then(function (value) { | ||
if (value && !res.headersSent) { | ||
res.send(value); | ||
} | ||
}) | ||
.catch(function (error) { return next(error); }); | ||
return [2 /*return*/]; | ||
} | ||
childContainer = this._container.createChild(); | ||
httpContext = this._getHttpContext(req); | ||
childContainer.bind(constants_1.TYPE.HttpContext) | ||
.toConstantValue(httpContext); | ||
result = (_a = childContainer.getNamed(constants_1.TYPE.Controller, controllerName))[key].apply(_a, args); | ||
Promise.resolve(result) | ||
.then(function (value) { | ||
if (value && !res.headersSent) { | ||
res.send(value); | ||
} | ||
}) | ||
.catch(function (error) { return next(error); }); | ||
return [2 /*return*/]; | ||
}); | ||
@@ -184,3 +212,7 @@ }); })(); | ||
}; | ||
InversifyExpressServer.prototype._getHttpContext = function (req, res, next) { | ||
InversifyExpressServer.prototype._getHttpContext = function (req) { | ||
var httpContext = Reflect.getOwnMetadata(constants_1.METADATA_KEY.httpContext, req); | ||
return httpContext; | ||
}; | ||
InversifyExpressServer.prototype._createHttpContext = function (req, res, next) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
@@ -187,0 +219,0 @@ var principal, httpContext; |
{ | ||
"name": "inversify-express-utils", | ||
"version": "5.0.0-beta.1", | ||
"version": "5.0.0", | ||
"description": "Some utilities for the development of express applications with Inversify", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
102
README.md
@@ -33,2 +33,3 @@ # inversify-express-utils | ||
To use a class as a "controller" for your express app, simply add the `@controller` decorator to the class. Similarly, decorate methods of the class to serve as request handlers. | ||
The following example will declare a controller that responds to `GET /foo'. | ||
@@ -93,5 +94,9 @@ | ||
// declare metadata by @controller annotation | ||
import "./controllers/foo_controller"; | ||
// set up container | ||
let container = new Container(); | ||
// set up bindings | ||
container.bind<FooService>('FooService').to(FooService); | ||
@@ -113,2 +118,28 @@ | ||
## Important information about the @controller decorator | ||
Since the `inversify-express-util@5.0.0` release. The `@injectable` annotation is no longer required in classes annotated with `@controller`. Declaring a type binding for controllers is also no longer required in classes annotated with `@controller`. | ||
:warning: Declaring a binding is not required for Controllers but **it is required to import the controller one unique time**. When the controller file is imported (e.g. `import "./controllers/some_controller"`) the class is declared and the metadata is generated. If you don't import it the metadata is never generated and therefore the controller is not found. An example of this can be found [here](https://github.com/inversify/inversify-express-example/blob/master/MongoDB/bootstrap.ts#L10-L11). | ||
If you run the application multiple times within a shared runtime process (e.g. unit testing) you might need to clean up the existing metadata before each test. | ||
```ts | ||
import { cleanUpMetadata } from "inversify-express-utils"; | ||
describe("Some Component", () => { | ||
beforeEach(() => { | ||
cleanUpMetadata(); | ||
}); | ||
it("Some test case", () => { | ||
// ... | ||
}); | ||
}); | ||
``` | ||
You can find an example of this in [our unit tests](https://github.com/inversify/inversify-express-utils/blob/master/test/framework.test.ts#L25-L29). | ||
## InversifyExpressServer | ||
@@ -272,3 +303,3 @@ | ||
If you are creating a custom controller you will need to inject `HttpContext` manually | ||
using the `@httpContext` decorator: | ||
using the `@injectHttpContext` decorator: | ||
@@ -286,3 +317,3 @@ ```ts | ||
@httpContext private readonly _httpContext: interfaces.HttpContext; | ||
@injectHttpContext private readonly _httpContext: interfaces.HttpContext; | ||
@authService private readonly _authService: AuthService; | ||
@@ -315,3 +346,3 @@ | ||
import { injectable, inject } from "inversify"; | ||
import {} from "inversify-express-utils"; | ||
import { interfaces } from "inversify-express-utils"; | ||
@@ -384,2 +415,65 @@ const authService = inject("AuthService"); | ||
## BaseMiddleware | ||
Extending `BaseMiddleware` allow us to inject dependencies | ||
and to be access the current `HttpContext` in Express middleware function. | ||
```ts | ||
import { BaseMiddleware } from "inversify-express-utils"; | ||
@injectable() | ||
class LoggerMiddleware extends BaseMiddleware { | ||
@inject(TYPES.Logger) private readonly _logger: Logger; | ||
public handler( | ||
req: express.Request, | ||
res: express.Response, | ||
next: express.NextFunction | ||
) { | ||
if (this.httpContext.user.isAuthenticated()) { | ||
this._logger.info(`${this.httpContext.user.details.email} => ${req.url}`); | ||
} else { | ||
this._logger.info(`Anonymous => ${req.url}`); | ||
} | ||
next(); | ||
} | ||
} | ||
``` | ||
We also need to declare some type bindings: | ||
```ts | ||
const container = new Container(); | ||
container.bind<Logger>(TYPES.Logger) | ||
.to(Logger); | ||
container.bind<LoggerMiddleware>(TYPES.LoggerMiddleware) | ||
.to(LoggerMiddleware); | ||
``` | ||
We can then inject `TYPES.LoggerMiddleware` into one of our controllers. | ||
```ts | ||
@injectable() | ||
@controller("/") | ||
class UserDetailsController extends BaseHttpController { | ||
@inject("AuthService") private readonly _authService: AuthService; | ||
@httpGet("/", TYPES.LoggerMiddleware) | ||
public async getUserDetails() { | ||
if (this.httpContext.user.isAuthenticated()) { | ||
return this._authService.getUserDetails(this.httpContext.user.details.id); | ||
} else { | ||
throw new Error(); | ||
} | ||
} | ||
} | ||
container.bind<interfaces.Controller>(TYPE.Controller) | ||
.to(UserDetailsController) | ||
.whenTargetNamed("UserDetailsController"); | ||
``` | ||
## Examples | ||
@@ -393,3 +487,3 @@ | ||
Copyright © 2016 [Cody Simms](https://github.com/codyjs) | ||
Copyright © 2016-2017 [Cody Simms](https://github.com/codyjs) | ||
@@ -396,0 +490,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
80434
29
1245
0
489