I've seen this mentioned a few times (, ), but I think it's worth revisiting.
My company manages multiple tornado-backed sites, and one problem we've had is the management of middleware-like logic across sites. For example, we use SQLAlchemy for our ORM. Currently on each of the sites we create a base controller that overrides on_finish to ensure per-request DB transactions are closed out.
Now, we could create a single common base controller that all controllers across all of the sites inherit. But there's a couple of problems:
Ideally, there would just be a way to hook this sort of logic into a site without resorting to creating a base controller - i.e. there would a middleware system. I think this would bring about better modularity, and in turn, get people to share tiny bits of tornado logic that might otherwise remain proprietary. I know we certainly would be happy to move our middleware-like logic into something open source.
This would be a pretty major change, so I'd like some opinions on whether this could feasibly be merged in - and what it might look like - before continuing forward. But I'm willing to code something up and submit a pull request.
One thing to bear in mind is that this might deprecate OutputTransforms, because they would be redundant. That would mean either this would have to be a breaking change, or the middleware engine would have to be designed to support backwards-compatibility with OutputTransforms.
I'm sympathetic to the problem of sharing code across tornado applications, but I don't really like the design of wsgi-style middleware (at least not for most of the things I've seen it used for). My thinking is that a better approach would be to move some of the overridable methods of RequestHandler to the Application or settings (similar to Application.log_request). The main methods I have in mind for this treatment are things like get_current_user and write_error.
prepare and on_finish are closer to wsgi middleware (but note that on_finish doesn't run until after the response has been written, so it can only do logging and cleanup). For these it might make sense to have a list of hooks. There's also no good way to insert a stack_context currently; it's messy even with a base class.
I admit I've generally worked on one big project for long periods of time rather than lots of little ones, so I'm not sure what the recurring problems are. I'd be interested in collecting feedback on the potential uses of a system like this.
I'm confused by your comment about putting the base controller in a separate python package. Wouldn't you have to do exactly the same thing with "middleware"? (and for your other point, you can actually customize static_url behavior via the static_handler_class application setting, although this isn't documented well).
And don't worry too much about OutputTransform. I'm not sure if anyone's using it externally, and it turns out to be the wrong design for one of the two things it's used for internally (according to the spec gzip has to be applied before anything relating to etags, while chunked encoding has to be after, so we can't satisfy both in the same way)
Here are the the bits of logic that we could turn into reusable middleware:
Moving things like get_current_user to the application/settings would help with a subset of these, but to accomodate most/all of this logic, we need a way of extending controllers in a pluggable manner.
My immediate intuition on how to approach this is to have a middleware engine that resembles OutputTransforms, except with more hooks that are called, e.g. at the initial request. It's not clear to me how executable logic would be exposed by middleware though. For example, if I enabled the blink middleware, I'd like to be able to simply call self.get_blink and self.set_blink in a controller to interact with it. But in order for middleware to accomodate this, it would have to attach methods to the controller at request time, which doesn't feel very pythonic.
Regarding packaging, if we turned this into middleware then admittedly these would be packaged up as well. But it would feel appropriate as we'd be able to open source it.
Also, FWIW, we use OutputTransform to gzip output -- so at least one company is using it externally :). It's pretty important to us because some of our API endpoints spit out some really redundant content so that it's easy to integrate with backbone. I wouldn't be surprised if a lot of people were unknowingly using OutputTransform by setting gzip=True in their application settings.
I'd like to have a middleware engine like the one described above as part of tornado core, but because of lack of activity on this ticket, we've gone ahead and written one that rests on top. We'll open source it once it proves stable enough in production.
@ysimonson I'm interested in seeing your middleware implementation. Any news on it? I'm interested in seeing your approach.
@tony yes, we developed this: https://github.com/dailymuse/oz
Here's a repo for bootstrapping a project: https://github.com/ysimonson/oz-bootstrap
We've been using it in production for ~6 months, but haven't announced anything yet.