module Hanami::Action::Mime
Mime
type API
@since 0.1.0
Constants
- CONTENT_TYPE
The header key to set the mime type of the response
@since 0.1.0 @api private
- DEFAULT_ACCEPT
The default mime type for an incoming HTTP request
@since 0.1.0 @api private
- DEFAULT_CHARSET
The default charset that is returned in the response
@since 0.3.0 @api private
- DEFAULT_CONTENT_TYPE
The default mime type that is returned in the response
@since 0.1.0 @api private
- HTTP_ACCEPT
The key that returns accepted mime types from the
Rack
env@since 0.1.0 @api private
- HTTP_CONTENT_TYPE
The key that returns content mime type from the
Rack
env@since 1.2.0 @api private
- MIME_TYPES
Most commom MIME Types used for responses
@since 1.0.0 @api private
Public Class Methods
Override Ruby's hook for modules. It includes Mime
types logic
@param base [Class] the target action
@since 0.1.0 @api private
@see www.ruby-doc.org/core-2.1.2/Module.html#method-i-included
# File lib/hanami/action/mime.rb, line 116 def self.included(base) base.class_eval do extend ClassMethods prepend InstanceMethods end end
Public Instance Methods
The charset that will be automatically set in the response.
It prefers, in order:
* Explicit set value (see #charset=) * Default configuration charset * Default content type
To override the value, use #charset=
@return [String] the charset of the request.
@since 0.3.0
@see Hanami::Action::Mime#charset=
@see Hanami::Configuration#default_charset @see Hanami::Action::Mime#default_charset
@see Hanami::Action::Mime#DEFAULT_CHARSET
@example
require 'hanami/controller' class Show include Hanami::Action def call(params) # ... charset # => 'text/html' end end
# File lib/hanami/action/mime.rb, line 360 def charset @charset || default_charset || DEFAULT_CHARSET end
Action
charset setter, receives new charset value
@return [String] the charset of the request.
@since 0.3.0
@example
require 'hanami/controller' class Show include Hanami::Action def call(params) # ... self.charset = 'koi8-r' end end
# File lib/hanami/action/mime.rb, line 327 def charset=(value) @charset = value end
The content type that will be automatically set in the response.
It prefers, in order:
* Explicit set value (see Hanami::Action::Mime#format=) * Weighted value from Accept header based on all known MIME Types: - Custom registered MIME Types (see Hanami::Controller::Configuration#format) * Configured default content type (see Hanami::Controller::Configuration#default_response_format) * Hard-coded default content type (see Hanami::Action::Mime::DEFAULT_CONTENT_TYPE)
To override the value, use #format=
@return [String] the content type from the request.
@since 0.1.0
@see Hanami::Action::Mime#format=
@see Hanami::Configuration#default_request_format @see Hanami::Action::Mime#default_content_type
@see Hanami::Action::Mime#DEFAULT_CONTENT_TYPE @see Hanami::Controller::Configuration#format
@see Hanami::Controller::Configuration#default_response_format
@example
require 'hanami/controller' class Show include Hanami::Action def call(params) # ... content_type # => 'text/html' end end
# File lib/hanami/action/mime.rb, line 304 def content_type return @content_type unless @content_type.nil? @content_type = content_type_from_accept_header if accept_header? @content_type || default_response_type || default_content_type || DEFAULT_CONTENT_TYPE end
Returns a symbol representation of the content type.
The framework automatically detects the request mime type, and returns the corresponding format.
However, if this value was explicitly set by `#format=`, it will return that value
@return [Symbol] a symbol that corresponds to the content type
@since 0.2.0
@see Hanami::Action::Mime#format=
@see Hanami::Action::Mime#content_type
@example Default scenario
require 'hanami/controller' class Show include Hanami::Action def call(params) end end action = Show.new _, headers, _ = action.call({ 'HTTP_ACCEPT' => 'text/html' }) headers['Content-Type'] # => 'text/html' action.format # => :html
@example Set value
require 'hanami/controller' class Show include Hanami::Action def call(params) self.format = :xml end end action = Show.new _, headers, _ = action.call({ 'HTTP_ACCEPT' => 'text/html' }) headers['Content-Type'] # => 'application/xml' action.format # => :xml
# File lib/hanami/action/mime.rb, line 267 def format @format ||= detect_format end
Private Instance Methods
@since 0.1.0 @api private
# File lib/hanami/action/mime.rb, line 529 def accept @accept ||= @_env[HTTP_ACCEPT] || DEFAULT_ACCEPT end
Match the given mime type with the Accept header
@return [Boolean] true if the given mime type matches Accept
@since 0.1.0
@example
require 'hanami/controller' class Show include Hanami::Action def call(params) # ... # @_env['HTTP_ACCEPT'] # => 'text/html,application/xhtml+xml,application/xml;q=0.9' accept?('text/html') # => true accept?('application/xml') # => true accept?('application/json') # => false # @_env['HTTP_ACCEPT'] # => '*/*' accept?('text/html') # => true accept?('application/xml') # => true accept?('application/json') # => true end end
# File lib/hanami/action/mime.rb, line 521 def accept?(mime_type) !!::Rack::Utils.q_values(accept).find do |mime, _| ::Rack::Mime.match?(mime_type, mime) end end
Checks if there is an Accept header for the current request.
@return [TrueClass,FalseClass] the result of the check
@since 0.8.0 @api private
# File lib/hanami/action/mime.rb, line 539 def accept_header? accept != DEFAULT_ACCEPT end
Patched version of Rack::Utils.best_q_match
.
@since 0.4.1 @api private
@see www.rubydoc.info/gems/rack/Rack/Utils#best_q_match-class_method @see github.com/rack/rack/pull/659 @see github.com/hanami/controller/issues/59 @see github.com/hanami/controller/issues/104 @see github.com/hanami/controller/issues/275
# File lib/hanami/action/mime.rb, line 602 def best_q_match(q_value_header, available_mimes) ::Rack::Utils.q_values(q_value_header).each_with_index.map do |(req_mime, quality), index| match = available_mimes.find { |am| ::Rack::Mime.match?(am, req_mime) } next unless match RequestMimeWeight.new(req_mime, quality, index, match) end.compact.max&.format end
Look at the Accept header for the current request and see if it matches any of the common MIME types (see Hanami::Action::Mime#MIME_TYPES) or the custom registered ones (see Hanami::Controller::Configuration#format
).
@return [String,Nil] The matched MIME type for the given Accept header.
@since 0.8.0 @api private
@see Hanami::Action::Mime#MIME_TYPES @see Hanami::Controller::Configuration#format
@api private
# File lib/hanami/action/mime.rb, line 556 def content_type_from_accept_header best_q_match(accept, configuration.mime_types) end
@since 0.3.0 @api private
# File lib/hanami/action/mime.rb, line 588 def content_type_with_charset "#{content_type}; charset=#{charset}" end
@since 0.3.0 @api private
# File lib/hanami/action/mime.rb, line 582 def default_charset configuration.default_charset end
@since 0.2.0 @api private
# File lib/hanami/action/mime.rb, line 568 def default_content_type self.class.format_to_mime_type( configuration.default_request_format ) if configuration.default_request_format end
@since 0.5.0 @api private
# File lib/hanami/action/mime.rb, line 562 def default_response_type self.class.format_to_mime_type(configuration.default_response_format) if configuration.default_response_format end
@since 0.2.0 @api private
# File lib/hanami/action/mime.rb, line 576 def detect_format configuration.format_for(content_type) || MIME_TYPES.key(content_type) end
Finalize the response by setting the current content type
@since 0.1.0 @api private
# File lib/hanami/action/mime.rb, line 372 def finish super headers[CONTENT_TYPE] ||= content_type_with_charset end
Sets the given format and corresponding content type.
The framework detects the `HTTP_ACCEPT` header of the request and sets the proper `Content-Type` header in the response. Within this default scenario, `#format` returns a symbol that corresponds to `#content_type`. For instance, if a client sends an `HTTP_ACCEPT` with `text/html`, `#content_type` will return `text/html` and `#format` `:html`.
However, it's possible to override what the framework have detected. If a client asks for an `HTTP_ACCEPT` `/`, but we want to force the response to be a `text/html` we can use this method.
When the format is set, the framework searches for a corresponding mime type to be set as the `Content-Type` header of the response. This lookup is performed first in the configuration, and then in `Hanami::Action::Mime::MIME_TYPES`. If the lookup fails, it raises an error.
PERFORMANCE: Because `Hanami::Controller::Configuration#formats` is smaller and looked up first than `Hanami::Action::Mime::MIME_TYPES`, we suggest to configure the most common mime types used by your application, **even if they are already present in that Rack
constant**.
@param format [#to_sym] the format
@return [void]
@raise [TypeError] if the format cannot be coerced into a Symbol @raise [Hanami::Controller::UnknownFormatError] if the format doesn't
have a corresponding mime type
@since 0.2.0
@see Hanami::Action::Mime#format
@see Hanami::Action::Mime#content_type
@see Hanami::Controller::Configuration#format
@example Default scenario
require 'hanami/controller' class Show include Hanami::Action def call(params) end end action = Show.new _, headers, _ = action.call({ 'HTTP_ACCEPT' => '*/*' }) headers['Content-Type'] # => 'application/octet-stream' action.format # => :all _, headers, _ = action.call({ 'HTTP_ACCEPT' => 'text/html' }) headers['Content-Type'] # => 'text/html' action.format # => :html
@example Simple usage
require 'hanami/controller' class Show include Hanami::Action def call(params) # ... self.format = :json end end action = Show.new _, headers, _ = action.call({ 'HTTP_ACCEPT' => '*/*' }) headers['Content-Type'] # => 'application/json' action.format # => :json
@example Unknown format
require 'hanami/controller' class Show include Hanami::Action def call(params) # ... self.format = :unknown end end action = Show.new action.call({ 'HTTP_ACCEPT' => '*/*' }) # => raise Hanami::Controller::UnknownFormatError
@example Custom mime type/format
require 'hanami/controller' Hanami::Controller.configure do format :custom, 'application/custom' end class Show include Hanami::Action def call(params) # ... self.format = :custom end end _, headers, _ = action.call({ 'HTTP_ACCEPT' => '*/*' }) headers['Content-Type'] # => 'application/custom' action.format # => :custom
# File lib/hanami/action/mime.rb, line 487 def format=(format) @format = Utils::Kernel.Symbol(format) @content_type = self.class.format_to_mime_type(@format) end