InversifyJS - Inject middleware into controller - inversifyjs

I'm using inversify-express-utils using the shortcut decorators (#GET, #POST...) within a node application.
Is it possible to inject middleware into the controller to use with these decorators?
Example of what I'm trying to achieve (doesn't work):
export class TestController implements Controller {
constructor(#inject(TYPES.SomeMiddleware) private someMiddleware: ISomeMiddleware) {}
#Get('/', this.someMiddleware.someMiddlewhereMethod())
public test() {
...
}
}

Like #OweR ReLoaDeD said, currently you can't do that with middleware injected through the controller constructor, due to the way decorators work in TypeScript.
However, you can achieve the same effect by wrapping the controller definition in a function that accepts a kernel, like so:
controller.ts
export function controllerFactory (kernel: Kernel) {
#injectable()
#Controller('/')
class TestController {
constructor() {}
#Get('/', kernel.get<express.RequestHandler>('Middleware'))
testGet(req: any, res: any) {
res.send('hello');
}
}
return TestController;
}
main.ts
let kernel = new Kernel();
let middleware: express.RequestHandler = function(req: any, res: any, next: any) {
console.log('in middleware');
next();
};
kernel.bind<express.RequestHandler>('Middleware').toConstantValue(middleware);
let controller = controllerFactory(kernel);
kernel.bind<interfaces.Controller>(TYPE.Controller).to(controller).whenTargetNamed('TestController');
let server = new InversifyExpressServer(kernel);
// ...
UPDATE
I added an example to the inversify-express-examples repo that showcases this approach using both custom and third-party middleware.

You should be able to use middleware please refer to the following unit tests as an example.
Update
I don't think that is possible because decorators are executed when the class is declared. The constructor injection takes place when the class instance is created (which is after it has been declared). This means that, when the decorator is executed, this.someMiddleware is null.
I'm afraid you won't be able to inject the middleware into the same class that uses it but you can do the following:
import { someMiddlewareMethod} from "middleware";
class TestController implements Controller {
#Get('/', someMiddlewareMethod())
public test() {
// ...
}
}
This is not a limitation of InversifyJS this is a limitation caused by the way decorators work.

Related

Inject service into class (not component) Angular2

I am struggling to find a way to inject a service into an class object in angular2.
* NOTE: This is not a component, just a class. *
export class Product {
id: number;
name: string;
manufacturer: string;
constructor(product: any) {
this.id = product.id;
this.name = product.name;
this.manufacturer = product.manufacturer;
}
The only solution I have come up with is to pass the service reference to the constructor whenever I create a new product... ie: instead of new Product(product) I would do new Product(product, productService) . This seems tedious and error prone. I would rather import the reference from the class and not messy up the constructor.
I have tried the ReflectiveInjector:
let injector = ReflectiveInjector.resolveAndCreate([ProductService]);
this.productService = injector.get(ProductService);
However, this creates an error No provider for Http! (ProductService -> Http) at NoProviderError.BaseError [as constructor] (Also I'm pretty sure this creates a new productService when I simple want to reference my singleton that is instantiated at the app level).
If anyone knows of a working solution I would be glad to hear it. For now i will pass the reference through the constructor.
Thanks
I was struggling with a similar issue, and what I ended up doing, was making the service a singleton as well as an Angular injectable.
This way you can inject via DI into Angular classes and call the static getInstance() method to get the singleton instance of the class.
Something like this:
import {Injectable} from "#angular/core";
#Injectable()
export class MyService {
static instance: MyService;
static getInstance() {
if (MyService.instance) {
return MyService.instance;
}
MyService.instance = new MyService();
return MyService.instance;
}
constructor() {
if (!MyService.instance) {
MyService.instance = this;
}
return MyService.instance;
}
}
There is no way to inject a service into a plain class. Angular DI only injects into components, directives, services, and pipes - only classes where DI creates the instance, because this is when injection happens.
To get Http from a custom injector, you need to add to it's providers like shown in Inject Http manually in angular 2
or you pass a parent injector that provides them
// constructor of a class instantiated by Angulars DI
constructor(parentInjector:Injector){
let injector = ReflectiveInjector.resolveAndCreate([ProductService]);
this.productService = injector.get(ProductService, parentInjector);
}
See also https://angular.io/docs/ts/latest/api/core/index/ReflectiveInjector-class.html

How to manually create and wire a service at runtime to a component in typescript Angular 2

Here's my use case:
I have an interface with 4 different implementations WorkflowA, WorkflowB, WorkflowC and WorkflowD.
export interface IWorkflow {
getQuestions();
validateQuestions();
getWorkflowSteps();
}
I have a WorkflowManager class that returns the appropriate workflow based on an input variable (Factory pattern?)
export class WorkflowManager {
workflow:IWorkflow;
getWorkflow(workflow){
switch (workflow) {
case 'workflowA':
return new workflowA();
case 'workflowB':
return new workflowB();
case 'workflowC':
return new workflowC();
case 'workflowD':
return new workflowD();
default:
throw new Error(`Unrecognized workflow: ${workflow}`);
}
}
}
I also have a component WorkflowComponent that gets loaded
Example:
/workflow=WorkflowA loads WorkflowComponent. The component then extracts the routeparam workflow and based on the value, it then passes it to the WorkflowManager which returns the appropriate workflow.
Here's a snippet of my component
#Component({
...
})
export class Workflow implements OnInit {
workflowInstance: IWorkflow;
constructor(
private route: ActivatedRoute,
private workflowManager: WorkflowManager,
) {
}
ngOnInit() {
this.route.params.subscribe(params => {
let regType: string = params['workflow'];
this.workflowInstance = this.workflowManager.getWorkflow(workflow);
});
}
}
But I don't like the idea of manually instantiating Workflow* classes. How can I improve this so I wire it using Angular2 supplied API so that it can be managed/injected in to other components?
Also in my current implementation, I will have to make ajax calls outside of Angular framework which I don't think is the best thing to do.
Any ideas on how to take advantage of the Angular framework and improve this?
One way is to inject an injector and acquire the workflow instance imperatively like:
#Injectable()
export class WorkflowManager {
constructor(private injector:Injector) {}
workflow:IWorkflow;
getWorkflow(workflow){
switch (workflow) {
case 'workflowA':
return this.injector.get(workflowA);
case 'workflowB':
return this.injector.get(workflowB);
case 'workflowC':
return this.injector.get(workflowC);
case 'workflowD':
return this.injector.get(workflowD);
default:
throw new Error(`Unrecognized workflow: ${workflow}`);
}
}
}
Alternatively you can inject workflowA, workflowB, workflowC, workflowA and just return the right one depending on the workflow but I think using the injector is a better fit for this use case.
Ensure you provide workflowA, workflowB, workflowC.

TypeScript: Access global type hidden by local class definition?

Lets assume i have a class which has the same name as an previously defined type which is defined inside lib.d.ts. How would i make use of that type within this class.
For example, i have the class Event, which has to deal with the browsers Event object, which is defined as an interface in lib.d.ts.
export class Event { // own definition of Event which hides original Event
public dealWithBrowserEvent(event: Event): void { // Event object defined by lib.d.ts
// deal with it
}
}
How would i tell Typescript that this are two different types. Of course i could simply rename my class, but i don't want to do that, because the name is perfect for my use case.
You can archive this by doing so:
E.ts:
class CustomEvent
{
public dealWithBrowserEvent(event: Event): void
{
}
}
export default CustomEvent;
A.ts:
import Event from './E'
export class SomeClass
{
//Parameter e here is instance of your CustomEvent class
public someMethod(e: Event): void
{
let be: any;
//get browser event here
e.dealWithBrowserEvent(be)
}
}
More on declaration merging, and what can be merged and what not: link
I strongly recommend you not doing so. This code will lead to a lot of confusion for your colleagues reading/modifying it later, let alone headache of not being able to use in the same file standard class for Event.
In the meantime i found a quite doable solution. I defined an additional module which exports renamed interfaces. If i import this module, i can use the renamed types as if they would be original types.
browser.ts
// Event will be the one from lib.d.ts, because the compiler does not know anything about
// the class Event inside this module/file.
// All defined properties will be inherited for code completion.
export interface BrowserEvent extends Event {
additionalProperty1: SomeType;
additionalProperty2: SomeType;
}
If you don't need additional properties you can just do type aliasing:
browser.ts
// Alias for Event
export type BrowserEvent = Event;
event.ts
import {BrowserEvent} from './browser.ts';
export class Event { // Definition of Event hides original Event, but not BrowserEvent
public dealWithBrowserEvent(event: BrowserEvent): void {
// deal with it
}
}
I'm quite happy with this solution, but maybe there is a even better solution.

Using my own service with Laravel4

In my app, I was testing Google Directions API with ajax, but since I was just testing all the logic was in the routes.php file. Now I want to do things the proper way and have three layers: route, controller and service.
So in the routes I tell Laravel which method should be executed:
Route::get('/search', 'DirectionsAPIController#search');
And the method just returns what the service is supposed to return:
class DirectionsAPIController extends BaseController {
public function search() {
$directionsSearchService = new DirectionsSearchService();
return $directionsSearchService->search(Input::all());
}
}
I created the service in app/libraries/Services/Directions and called it DirectionsSearchService.php and copied all the logic I developed in routes:
class DirectionsSearchService {
public function search($input = array()) {
$origin = $input['origin'];
$destination = $input['destination'];
$mode = $input['mode'];
// do stuf...
return $data;
}
}
I read the docs and some place else (and this too) and did what I was supposed to do to register a service:
class DirectionsAPIController extends BaseController {
public function search() {
App::register('libraries\Services\Directions\DirectionsSearchService');
$directionsSearchService = new DirectionsSearchService();
return $directionsSearchService->search(Input::all());
}
}
// app/libraries/Services/Directions/DirectionsSearchService.php
use Illuminate\Support\ServiceProvider;
class DirectionsSearchService extends ServiceProvider {
}
I also tried adding libraries\Services\Directions\DirectionsSearchService to the providers array in app/config/app.php.
However, I am getting this error:
HP Fatal error: Class
'libraries\Services\Directions\DirectionsSearchService' not found in
/home/user/www/my-app-laravel/bootstrap/compiled.php on line 549
What am I doing wrong? And what is the usual way to use your own services? I don't want to place all the logic in the controller...
2 main things that you are missing:
There is a difference between a ServiceProvider and your class. A service provider in Laravel tells Laravel where to go look for the service, but it does not contain the service logic itself. So DirectionsSearchService should not be both, imho.
You need to register your classes with composer.json so that autoloader knows that your class exists.
To keep it simple I'll go with Laravel IoC's automatic resolution and not using a service provider for now.
app/libraries/Services/Directions/DirectionsSearchService.php:
namespace Services\Directions;
class DirectionsSearchService
{
public function search($input = array())
{
// Your search logic
}
}
You might notice that DirectionsSearchService does not extend anything. Your service becomes very loosely coupled.
And in your DirectionsAPIController.php you do:
class DirectionsAPIController extends BaseController
{
protected $directionsSearchService;
public function __construct(Services\Directions\DirectionsSearchService $directionsSearchService)
{
$this->directionsSearchService = $directionsSearchService;
}
public function search()
{
return $this->directionsSearchService->search(Input::all());
}
}
With the code above, when Laravel tries to __construct() your controller, it will look for Services\Directions\DirectionsSearchService and injects into the controller for you automatically. In the constructor, we simply need to set it to an instance variable so your search() can use it when needed.
The second thing that you are missing is to register your classes with composer's autoload. Do this by adding to composer.json's autoload section:
"autoload": {
"classmap": [
... // Laravel's default classmap autoloads
],
"psr-4": {
"Services\\": "app/libraries/Services"
}
}
And do a composer dump-autoload after making changes to composer.json. And your code should be working again.
The suggestion above can also be better with a service provider and coding to the interface. It would make it easier to control what to inject into your controller, and hence easier to create and inject in a mock for testing.
It involves quite a few more steps so I won't mention that here, but you can read more in Exploring Laravel’s IoC container and Laravel 4 Controller Testing.

Zend Framework: How to inject a controller property from a Zend_Controller_Plugin

I wrote a plugin that needs to set a property on the controller that's currently being dispatched. For example, if my plugin is:
class Application_Plugin_Foo extends Zend_Controller_Plugin_Abstract
{
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
{
// Get an instance of the current controller and inject the $foo property
// ???->foo = 'foo';
}
}
I want to be able to do this:
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$this->view->foo = $this->foo;
}
}
}
Any help is greatly appreciated!
The action controller is not directly accessible directly from a front-controller plugin. It's the dispatcher that instantiates the controller object and he doesn't appear to save it anywhere accessible.
However, the controller is accessible from any registered action helpers. Since action helpers have a preDispatch hook, you could do your injection there.
So, in library/My/Controller/Helper/Inject.php:
class My_Controller_Helper_Inject extends Zend_Controller_Action_Helper_Abstract
{
public function preDispatch()
{
$controller = $this->getActionController();
$controller->myParamName = 'My param value';
}
}
Then register an instance of the helper in application/Bootstrap.php:
protected function _initControllerInject()
{
Zend_Controller_Action_HelperBroker::addHelper(
new My_Controller_Helper_Inject()
);
}
And, as always, be sure to include My_ as an autoloader namespace in configs/application.ini:
autoloaderNamespaces[] = "My_"
Then, in the controller, access the value directly as a public member variable:
public function myAction()
{
var_dump($this->myParamName);
}
One thing to note: Since the helper uses the preDispatch() hook, I believe it will get called on every action, even an internal forward().
Browsing through the API, I didn't find a way to reach the controller directly (I'm guessing this loop is performed before the controller exists). What I could find is almost as easy to access, albeit with a bit different syntax.
Via request params
class Application_Plugin_Foo extends Zend_Controller_Plugin_Abstract
{
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
{
$yourParam = 'your value';
if($request->getParam('yourParam')) {
// decide if you want to overwrite it, the following assumes that you do not care
$request->setParam('yourParam', $yourParam);
}
}
}
And in a Zend_Controller_Action::xxxAction():
$this->getParam('yourParam');
Via Zend_Controller_Action_Helper_Abstract
There's another way mentioned in MWOP's blog, but it takes the form of an action helper instead: A Simple Resource Injector for ZF Action Controllers. His example would let you access any variable in Zend_Controller_Action as $this->yourParam.