jeffijoe / awilix-express

Awilix helpers/middleware for Express
MIT License
114 stars 7 forks source link

[question] "@before" middleware with injected dependencies #22

Closed addemod closed 4 years ago

addemod commented 4 years ago

Hello.

I have no idea if this is possible or not, but I can't seem to find a way to make this work. Let's say I have this class:

export class AuthorizationMiddlewares {

    tokenManager: TokenManager

    constructor({ tokenManager }) {
        this.tokenManager = tokenManager
    }

    async authorize(req, res, next) {
        try {
            const token = await this.tokenManager.getByAccessToken(this.getAuthorizationToken(req))
            await this.tokenManager.validate(token.accessToken)
            req.token = token
            next()
        }catch(error) {
            next(error)
        }
    }

    getAuthorizationToken(req): string {
      // blabla
      return "blabla"
    }
}

and I want to use it as a middleware, the question is how? Inside the route class, in @before, I cannot use the injected AuthorizationMiddlewares class, as I cannot access the route's instance variables. I read something about @inject but I am not sure if that's the way to go.

My route class looks like this:

@route('/users')
export default class UserAPI {

    authorizationMiddlewares: AuthorizationMiddlewares

    constructor({ authorizationMiddlewares }) {
        this.authorizationMiddlewares = authorizationMiddlewares
    }

    @route("/test")
    @before(this.authorizationMiddleware.authorize) // this is not possible
    @GET()
    async test(req, res) {
        try {
            res.json({ test: true })           
        }catch(error) {
            next(error)
        }
        const role: any = await Role.findByName("user")
        res.json(role)
    }
}

I am aware that I can import AuthorizationMiddlewares directly, but that won't let me inject the token manager class.

Please help :)

jeffijoe commented 4 years ago

You will have a much easier time if you use a factory function instead, then you can use @before(inject(authorize)).

export function authorize({ tokenManager }) {
  return async (req, res, next) => {
    try {
      const token = await tokenManager.getByAccessToken(getAuthorizationToken(req))
      await tokenManager.validate(token.accessToken)
      req.token = token
      next()
    } catch(error) {
      next(error)
    }
  }

  function getAuthorizationToken(req) {
    // blabla
    return "blabla"
  }
}