Mounting Rack Middleware at the action level

Hello, I think that mounting rack middleware at the action level was possible in Hanami 1.3. I wanted to leverage this way of doing so to make some nice integration with rodauth.

I found this page for the v2.0: V2.0: Rack integration | Hanami Guides, which says that it’s still possible:

Hanami mounts a thin default middleware stack. Additional middleware can be mounted either at application level, in the router, or for an individual action.

But there’s no example how to do it. I tried with use, config.middleware.use but none of the methods were found in hanami action class or action config.

I also found this open issue somebody faced while making a research o that topic: Middlewares at action level · Issue #1301 · hanami/hanami · GitHub but the solution seems a bit hacky to me.

TLDR which should be on the top, probably: so is it steel possible? If so, how? If not: is it planned to support mounting middleware at the action level?

@buszu Exploring the hanami repo code-base’s main branch I could notice following:

In action a middleware named rack_monitor is available. See below.

That is made available by following

Infact if you notice L1050-1057 you can see sessions and content_security_policy middlewares for actions are also made available.

Their implementation can be found at

hanami/hanami/blob/7f957dc44b823a976af5ff74797e2ae6fdf8be69/lib/hanami/config/actions/sessions.rb

hanami/hanami/blob/7f957dc44b823a976af5ff74797e2ae6fdf8be69/lib/hanami/config/actions/content_security_policy.rb

Ofcourse those are supported for pre-identified config options. But using following config option (ref: V2.2: App config | Hanami Guides)

config.middleware.use MyMiddleware, "middleware", "args", "here"

you can try implementing a middleware - on lines of those action-specific middlewares - and maybe that can help you achieve your goal.

I would suggest to see how hanami/hanami/blob/7f957dc44b823a976af5ff74797e2ae6fdf8be69/lib/hanami/middleware/content_security_policy_nonce.rb is implemented and how it is included in the middleware stack when content_security_policy is found enabled for actions (see below)

hanami/hanami/blob/7f957dc44b823a976af5ff74797e2ae6fdf8be69/lib/hanami/slice.rb#L1054-L1056

Please note that this content-security-policy specific options support is only available on main branch code. They are not part of the latest release version 2.2.1.

Hope this turns out helpful.

Thanks.

To include into the routes, at the desired level, I do like that

scope 'plop' do
   use My::Middlewares::StuffHandler
   get  "/status", to: "v1.utils.status", as: :utils_status
end

try it and let us know ?

1 Like

Thanks, of course mounting on the router level works and we can scope there.

I rather want to confront what the docs say with the reality :slight_smile:

So my question is if there are any plans to support mounting inside the actions via any public API or if the docs are misleading a bit, and mounting for individual actions is only possible by scoping in routing.

1 Like

Hi @buszu, thanks for following this up :slight_smile:

In this case, it’s our documentation that’s not correct. In Hanami Controller 2.x, we do not provide the ability to mount Rack middleware directly inside actions.

I suspect this mention in the docs was an overlooked carry-over from their 1.x versions. I’ll fix that now.

To help with deciding whether to reintroduce this feature, I’m interested to hear what use case(s) you had in mind for it. Feel free to share whenever you have the time :slight_smile: Thanks!

2 Likes

Thanks for making it clear.

I was just trying to sketch hanami 2 + rodauth, and wanted to use rodauth middleware feature.

Given that, it thought it would be nicer to mount rodauth app in the action and have it there, rather than leverage routing.

It would be then just a kind of „before hook” but on the middleware level, and I wouldn’t have to check the routing to know whether the action is protected with auth or not.

But maybe you already have better recipes for hanami 2 & rodauth?

I am using rodauth with Hanami 2.2 and it works great:

# frozen_string_literal: true

module InhouseGate
  class Routes < Hanami::Routes
    slice :auth, at: "/auth" do
      use Auth::RodauthApp
      get "/realms/:realm/userinfo", to: "realms.userinfo"
    end
  end
end

Never thought about integrating it into the action level.

Maybe I’m used to the setup where it’s the action where I decide if it’s authenticated or not.

Also I have a feeling that actions level is more granular than routing.

Anyway, probably I wouldn’t mind mounting it in the routing if it’s the recommended way.