Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inversify-express-utils: Inject server level middleware #453

Open
RPallas92 opened this issue May 7, 2018 · 6 comments
Open

Inversify-express-utils: Inject server level middleware #453

RPallas92 opened this issue May 7, 2018 · 6 comments

Comments

@RPallas92
Copy link

I don't see a clear way to inject server level express middleware, if that middleware has HttpContext as dependency.

Expected Behavior

    const expressServer = new InversifyExpressServer(inversifyContainer, null, { rootPath: apiPrefix })
    expressServer.setConfig((app: express.Application) => {
        const authMiddleware = inversifyContainer.get<AuthorizationMiddleware>(TYPES.AuthorizationMiddleware)
        app.use(authMiddleware.middleware())
        
    })

Middleware is injected at setConfig level.

Current Behavior

The following error is thrown:
No matching bindings found for serviceIdentifier: Symbol(HttpContext)

@josete89
Copy link

josete89 commented May 7, 2018

+1

1 similar comment
@jlopezmartinez
Copy link

+1

@dcherman
Copy link
Contributor

Since HttpContext can only ever exist in a per request scope and at the time that top level middleware is bound, that can't be available, the way that you're trying to do this will probably not be feasible.

Looking at the code, there is no point in time where you can inject a global middleware that can receive per request injections.

let result = childContainer.getNamed<any>(TYPE.Controller, controllerName)[key](...args);

Probably wouldn't be a bad idea to implement something like Web API's various filter interfaces like https://msdn.microsoft.com/en-us/library/system.web.http.filters.iauthenticationfilter(v=vs.118).aspx

(Not a maintainer here, just a drive by suggestion)

@kalahari
Copy link
Contributor

It is possible to derive the HttpContext from the Request at run time, but not from a documented API, so it may cease to work in the future:

Reflect.getMetadata('inversify-express-utils:httpcontext', req);

I use a base middleware with a static method to help register server level middleware. (It manages async handlers as well.) The helper method does need direct access to your DI container to create a new instance of the middleware for each request.

import { NextFunction, Request, Response } from 'express-serve-static-core';
import { Container, injectable } from 'inversify';
import { BaseMiddleware as InversifyBaseMiddleware } from 'inversify-express-utils';

export type MiddlewareFunction = (req: Request, res: Response, next: NextFunction) => void;
export interface IMiddleware {
    handler: MiddlewareFunction;
}

@injectable()
export abstract class BaseMiddleware extends InversifyBaseMiddleware implements IMiddleware {
    public static getHttpContext(req: Request) {
        // FIXME: playing in inversify-express-utils' sandbox
        return Reflect.getMetadata(
            'inversify-express-utils:httpcontext',
            req,
        );
    }

    public static serverHandler(di: Container, middlewareToken: symbol): MiddlewareFunction {
        return (req: Request, res: Response, next: NextFunction) => {
            const middleware = di.get<BaseMiddleware>(middlewareToken);
            // cast to any to allow writing of httpContext
            (middleware as any).httpContext = BaseMiddleware.getHttpContext(req);
            middleware.handler(req, res, next);
        };
    }

    public handler(req: Request, res: Response, next: NextFunction) {
        try {
            const result = this.handle(req, res, next);
            if (result != null && typeof (result as Promise<void>).then === 'function') {
                Promise.resolve(result).catch(err => next(err));
            }
        } catch (err) {
            next(err);
        }
    }

    protected abstract handle(req: Request, res: Response, next: NextFunction): Promise<void> | void;
}

Assuming I have FooMiddlware that derives from BaseMiddleware bound to symbol FooMiddlewareToken, registering it for all requests looks like this:

const fooHandler = BaseMiddleware.serverHandler(container, FooMiddlewareToken);
app.use(fooHandler);

@PodaruDragos
Copy link
Contributor

@notaphplover @dcavanagh do you think we can maybe do something to actually be able to @inject into the setErrorConfig function ?

I don't think we can actually apply any decorators before the .build() function tbh, I'll want to look into this, but I really need a second opinion here.

@notaphplover
Copy link
Member

Hi @PodaruDragos I need to do some research, I'm almost new to the inversify-express-utils project

@notaphplover notaphplover transferred this issue from inversify/InversifyJS Feb 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

No branches or pull requests

7 participants