Actions: MIME Types


Actions have advanced features for MIME Type detection, automatic headers, whitelisting etc..

Request Introspection

In order to understand what the requested MIME Type is, an action looks at the Accept request header and exposes a high level API: #format and #accept?.

The first returns a symbol representation of the MIME Type (eg. :html, :json, :xml etc..), while the second is a query method that accepts a MIME type string and checks if it’s accepted by the current browser.

# apps/web/controllers/dashboard/index.rb
module Web
  module Controllers
    module Dashboard
      class Index
        include Web::Action

        def call(params)
          puts format                     # => :html

          puts accept?('text/html')       # => true
          puts accept?('application/png') # => false
        end
      end
    end
  end
end

Automatic Content-Type

An action returns the Content-Type response header automatically according to the requested MIME Type and charset.

If the client asks for Accept: text/html,application/xhtml+xml,application/xml;q=0.9, the action will return Content-Type: text/html; charset=utf-8.

Default Request Format

If a client asks for a generic Accept: */*, the action will fall back to the application default format. This is a setting that allows us to safely handle cases like our example; the default value is :html.

# apps/web/application.rb

module Web
  class Application < Hanami::Application
    configure do
      # ...
      default_request_format :json
    end
  end
end

Default Response Format

If we are building a JSON API app, it can be useful to specify a :json as default MIME Type for the response. The default value is :html.

# apps/web/application.rb

module Web
  class Application < Hanami::Application
    configure do
      # ...
      default_response_format :json
    end
  end
end

Default Charset

Similarly, we can specify a different default charset to return. The standard value is utf-8, but we can change it in our settings.

# apps/web/application.rb

module Web
  class Application < Hanami::Application
    configure do
      # ...
      default_charset 'koi8-r'
    end
  end
end

Override

There is a way we can force the returned Content-Type: use #format=.

# apps/web/controllers/dashboard/index.rb
module Web
  module Controllers
    module Dashboard
      class Index
        include Web::Action

        def call(params)
          puts self.format # => :html

          # force a different value
          self.format        =  :json
          puts self.format # => :json
        end
      end
    end
  end
end

The example above will return Content-Type: application/json; charset=utf-8.

Whitelisting

We can also restrict the range of accepted MIME Types. If the incoming request doesn’t satisfy this constraint, the application will return a Not Acceptable status (406).

# apps/web/controllers/dashboard/index.rb
module Web
  module Controllers
    module Dashboard
      class Index
        include Web::Action
        accept :html, :json

        def call(params)
          # ...
        end
      end
    end
  end
end

Register MIME Types

Hanami knows about more than 100 of the most common MIME types. However, we may want to add custom types in order to use them with #format= or .accept.

In our application settings we can use controller.format, which accepts a Hash where the key is the format symbol (:custom) and the value is a string expressed in the MIME type standard (application/custom).

# apps/web/application.rb

module Web
  class Application < Hanami::Application
    configure do
      # ...
      controller.format custom: 'application/custom'
    end
  end
end