Code Monkey home page Code Monkey logo

Comments (9)

jeffijoe avatar jeffijoe commented on June 14, 2024

@IGZgustavomarin you can use inject to have Awilix build the middleware:

const { createController, inject } = require('awilix-express')
// Assuming `cacheMiddleware` is a factory function
const { cacheMiddleware } = require('./your/cache/middleware')

class TodoController {
  constructor ({ todosService }) {
    this.todos = todoService
  }
  
  getAll(req, res) => {
    return res.send(this.todosService.getTodos())
  }
  
}

module.exports = createController(TodoController)
  .get('/todos', 'getAll', {
    before: [ inject(cacheMiddleware) ]
  })

from awilix-express.

 avatar commented on June 14, 2024

Ok, this way works, but my middleware gets created each time I call the endpoint. Even if I set the lifetime to SINGLETON. I'm doing this:

const cacheProducts = ({ config }) => {
   return (req, res, next) => {
     /** cache logic here, return memory data or return next() **/  
  }
  return cache
}

cacheProducts[RESOLVER] = {
  lifetime: Lifetime.SINGLETON
}
module.exports = cacheProducts

Is is possible to inject the same middleware every time? Otherwise, it never hits my cache data.

FYI: All this was working on previous version with code like this:

classs ProductsRouter {
/** code **/
this.router = Router()
this.router.get('/products', 
   cacheProductsMiddleware, // cache layer
   inject('getAllProducts'),  // data access layer
   this.getAll // <- the endpoint handler
)

from awilix-express.

jeffijoe avatar jeffijoe commented on June 14, 2024

Lifetimes only apply to registrations, not resolvers built directly with container.build (which is what inject does), so you want to wrap it to use the registration:

module.exports = createController(TodoController)
  .get('/todos', 'getAll', {
    // assuming your middleware registration is named "cacheService"
    before: [ inject(({ cacheService }) => cacheService) ]
  })

from awilix-express.

jeffijoe avatar jeffijoe commented on June 14, 2024

In fact, Awilix has a resolver for this called aliasTo which does exactly what the previous example does:

const { aliasTo } = require('awilix')

module.exports = createController(TodoController)
  .get('/todos', 'getAll', {
    // assuming your middleware registration is named "cacheService"
    before: [ inject(aliasTo('cacheService')) ]
  })

Hope this helps. 😄

from awilix-express.

 avatar commented on June 14, 2024

Ok, now the middleware gets injected each time. But the cache layer makes some patching to the Response object that doesn't work with inject, meaning it never cache anything. I think the middleware function that inject actually adds, collides with the apicache (npm module) that I'm using.

Is there a way to create a controller and register the routes differently?

from awilix-express.

jeffijoe avatar jeffijoe commented on June 14, 2024

But the cache layer makes some patching to the Response object that doesn't work with inject, meaning it never cache anything

How so?

How do you register cacheService? It would have to be singleton. Also, that cacheProducts middleware has return cache as well as return (req, res) => ..., is that a typo in the example?

Could you try creating a minimal reproduction repository? That would make it way easier for me to help you, cause I'm certain we can make it work. 😄

from awilix-express.

 avatar commented on June 14, 2024

Finally solve it. It turns out that the cache layer didn't work with HEAD request only and that was messing my example. It works as intended. Sorry about that!

I've separated the logic into two controllers, like this:

mainRouter
 .use(loadControllers('cache/*'))
 .use(loadControllers('products/*'))

Each of those folders contains a class wrapped with a createController call. But I noticed that on each request a new instance is created. This is too expensive for the cache layer (ex: connection, warmup, etc). Is it possible to make that instance a singleton?

My cache controllers is as this:

class ProductsCache {
  constructor ({ config }) {
    /** THIS IS CALLED ON EACH REQUEST **/
    this.cacheAll = apicache.options({
       ...(config.cache.defaultConfig),
       enabled: config.cache.defaultConfig.enabled === 'yes'
      })
      .middleware(config.cache.expiration.productList)
    }
    
	deleteAll = (req, res) => {
      res.send(apicache.clear('/api/products'))
    }

}

module.exports =  createController(ProductsCache)
  .get('/api/products', 'cacheAll')
  .delete('/api/products/_cache', 'deleteAll')

I tried as a function instead of class, but it also gets called on each request. Can that behavior be changed?

from awilix-express.

jeffijoe avatar jeffijoe commented on June 14, 2024

The whole point is for the controller to be instantiated with each request, so you can inject request-specific stuff in the constructor. 😄

Seems to me you want the apicache to be a singleton.

// In your container config
const apicache = require('apicache')

container.register({
  productCache: asFunction(
    ({ config }) => 
      apicache
        .options({
          ...(config.cache.defaultConfig),
          enabled: config.cache.defaultConfig.enabled === 'yes'
        })
        .middleware(config.cache.expiration.productList)
    )
    .singleton()
})

// Controller
class ProductsCache {
  constructor ({ productCache }) {
    this.cacheAll = productCache
  }
    
  deleteAll = (req, res) => {
    res.send(apicache.clear('/api/products'))
  }

}

module.exports =  createController(ProductsCache)
  .get('/api/products', 'cacheAll')
  .delete('/api/products/_cache', 'deleteAll')

from awilix-express.

 avatar commented on June 14, 2024

Thanks, I did something similar to that. 🎉

from awilix-express.

Related Issues (19)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.