Middy: Interrupt middleware but run `after` phases of called middlewares

Created on 18 Jan 2019  路  6Comments  路  Source: middyjs/middy

Is it possible that a middleware stops the execution of all middlewares after a middleware and NOT call the handler itself but to only call the after phases of the already run middlewares? We need this to clean up and log stuff.

A use case is a middleware which stops OPTIONS calls so that the cors middleware can handle these requests.

Most helpful comment

That's how I'm exiting the chain early right now, by calling handler.callback(null, '<desired response>') but the key limitation here is that this approach bypasses all of the after middleware that you may have configured.

So the goal would be to allow a way that a before middleware could decide to stop progressing through the middleware chain, skipping subsequent middleware and the handler, but still trigger any after middleware that should apply.

All 6 comments

Hello @thomaschaaf, sorry for the very late reply (busy times...).

With the "suggested" approach this is not possible.

I am not sure if there's a clean way to do this at the moment.

One way might be to avoid the early return, just populate the handler.response value in your middleware and just invoke next().

If you do this, you will have to be careful and make sure no other middleware modifies the response. You might use some special flag to do that, but your code might get convoluted.

I am thinking if it could make sense to introduce a new middleware phase in a future version of middy called cleanup or finally to deal with this need in a more clean and obvious way.

@theburningmonk, @vladgolubev, @dkatavic, @DavidWells what do you think?

I really like the idea of a finally phase. Would this have to be discussed or would a PR be welcome?

I've been using middy for a while now and this is my biggest hangup. The inability to stop the 'before' middleware chain early and still execute the appropriate 'after' middleware has been quite limiting for me.

I wrote a quick alternative implementation which changes the signature of the before middlewares from the current approach

(handler, next) => {
  ... do stuff
  next()
}

to something that enables alternative ways to continue the chain

(handler, chain) => {
  if (handler.event.session === null) {
    chain.end()
  } else {
    chain.next()
  }
}

I'm curious if this is something that would be considered?

My use case for middy is almost exclusively for use with http based api endpoints so admittedly that's the context i'm focused on. Given that this would be an api breaking change I can understand be cautious.

Hello @agilliland. Thanks a lot for your example here.
I like the idea you are proposing, but, at first glance, I still feel that introducing a finally phase would be a cleaner and easier alternative.
I am a bit tired right now, so I might not be thinking totally straight or missing some important detail. I promise I'll revisit this soon with a bit more focus 馃槗

Meanwhile @willfarrell, any opinion on this from your side? :)

The first thing I thought of was the warmup middleware when I read the above. It does exactly this, exit the chain early. It does it by calling the handler callback like this: return handler.callback(null, 'warmup'). It's not the most intuitive, but it is in there.

I like the idea of the chain param. However, I know for v2 we'd like to deprecate the use of callbacks in favour of async/await, not sure how this would affect this idea. Still, discussions and thinking to be had of course. If we had a chain.done param, it would just be a wrapper around the handler.callback or something similar. We'll definitely consider this when/if we make changes.

Added to the v2 list so that it's not missed.

That's how I'm exiting the chain early right now, by calling handler.callback(null, '<desired response>') but the key limitation here is that this approach bypasses all of the after middleware that you may have configured.

So the goal would be to allow a way that a before middleware could decide to stop progressing through the middleware chain, skipping subsequent middleware and the handler, but still trigger any after middleware that should apply.

Was this page helpful?
0 / 5 - 0 ratings