Before hook on multiple routes

Hi,

In a Sinatra app, within a namespace, I can put code that decomposes a JWT to retreive a userid. That code is run for all the API endpoints within that namespace. So it is actually a before-hook that runs before all routes of the namespace.

How should I do this in a Hanami 2.1 app?

Kind regards,

Thibaut

@thieb

Solution: You can use inheritance.

In your base action (app/action.rb) put:

module YourApp
  class Action < Hanami::Action
    before :authenticate

    private

    def authenticate
      # decode JWT
    end
  end
end

Because your actions inherit from YourApp::Action, now they will execute that before callback.

In case you want to opt-out the authentication in an action, just override with an empty method:

module YourApp
  module Actions
    module Foo
      class Something < YourApp::Action

      def handle(req, res)
        # ...
      end

      private

      # Empty-method skips the authentication
      def authenticate
      end
    end
  end
end

Bonus:

What I usually do in my apps is to create a module in app/actions/authentication.rb:

module MyApp
  module Actions
    module Authentication
      module Skip
        private

        # Skip authentication
        def authenticate
        end
      end

      private

      def authenticate
        # Authentication logic goes here
      end
    end
  end
end

Then I inject it in the base action (app/action.rb):

module MyApp
  class Action < Hanami::Action
    include Actions::Authentication
  end
end

In case I want to opt-out the authentication in an action, I include the following module:

module MyApp
  module Actions
    module Foo
      class Something < YourApp::Action
        include Authentication::Skip

        def handle(req, res)
        end
      end
    end
  end
end

Reminder

With Hanami you should always ask yourself: how would I solve this problem with Ruby?

4 Likes