Skip to content

Commit

Permalink
Encapsulate all format config in Config::Formats, reorganise Mime
Browse files Browse the repository at this point in the history
  • Loading branch information
timriley committed Nov 18, 2022
1 parent 2e025d2 commit fe5a515
Show file tree
Hide file tree
Showing 14 changed files with 673 additions and 543 deletions.
6 changes: 0 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -928,12 +928,6 @@ configuration = Hanami::Controller::Configuration.new do |config|
#
config.format custom: "application/custom"

# Define a fallback format to detect in case of HTTP request with `Accept: */*`
# If not defined here, it will return Rack's default: `application/octet-stream`
# Argument: symbol, it should be already known. defaults to `nil`
#
config.default_request_format = :html

# Define a default format to set as `Content-Type` header for response,
# unless otherwise specified.
# If not defined here, it will return Rack's default: `application/octet-stream`
Expand Down
1 change: 1 addition & 0 deletions hanami-controller.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
spec.add_dependency "rack", "~> 2.0"
spec.add_dependency "hanami-utils", "~> 2.0.0.rc1"
spec.add_dependency "dry-configurable", "~> 1.0", "< 2"
spec.add_dependency "dry-core", "~> 1.0"
spec.add_dependency "zeitwerk", "~> 2.6"

spec.add_development_dependency "bundler", ">= 1.6", "< 3"
Expand Down
49 changes: 10 additions & 39 deletions lib/hanami/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,7 @@ def self.gem_loader

# See {Config} for individual setting accessor API docs
setting :handled_exceptions, default: {}
setting :formats, default: Config::DEFAULT_FORMATS
setting :default_request_format, constructor: -> (format) {
Utils::Kernel.Symbol(format) unless format.nil?
}
setting :default_response_format, constructor: -> (format) {
Utils::Kernel.Symbol(format) unless format.nil?
}
setting :accepted_formats, default: []
setting :formats, default: Config::Formats.new, mutable: true
setting :default_charset
setting :default_headers, default: {}, constructor: -> (headers) { headers.compact }
setting :cookies, default: {}, constructor: -> (cookie_options) {
Expand All @@ -77,8 +70,8 @@ def self.gem_loader
Pathname(File.expand_path(dir || Dir.pwd)).realpath
}
setting :public_directory, default: Config::DEFAULT_PUBLIC_DIRECTORY
setting :before_callbacks, default: Utils::Callbacks::Chain.new, cloneable: true
setting :after_callbacks, default: Utils::Callbacks::Chain.new, cloneable: true
setting :before_callbacks, default: Utils::Callbacks::Chain.new, mutable: true
setting :after_callbacks, default: Utils::Callbacks::Chain.new, mutable: true

# @!scope class

Expand All @@ -87,7 +80,7 @@ def self.gem_loader
#
# @example Access inside class body
# class Show < Hanami::Action
# config.default_response_format = :json
# config.format :json
# end
#
# @return [Config]
Expand Down Expand Up @@ -278,34 +271,12 @@ def self.prepend_after(...)
config.after_callbacks.prepend(...)
end

# Restrict the access to the specified mime type symbols.
#
# @param formats[Array<Symbol>] one or more symbols representing mime type(s)
#
# @raise [Hanami::Action::UnknownFormatError] if the symbol cannot
# be converted into a mime type
#
# @since 0.1.0
#
# @see Config#format
#
# @example
# require "hanami/controller"
#
# class Show < Hanami::Action
# accept :html, :json
#
# def handle(req, res)
# # ...
# end
# end
#
# # When called with "*/*" => 200
# # When called with "text/html" => 200
# # When called with "application/json" => 200
# # When called with "application/xml" => 415
def self.accept(*formats)
config.accepted_formats = formats
# @since 2.0.0
# @api public
def self.format(...)
config.format(...)
end

# @see Config#handle_exception
Expand Down Expand Up @@ -343,7 +314,7 @@ def call(env)
response = build_response(
request: request,
config: config,
content_type: Mime.calculate_content_type_with_charset(config, request, config.accepted_mime_types),
content_type: Mime.response_content_type_with_charset(request, config),
env: env,
headers: config.default_headers,
sessions_enabled: sessions_enabled?
Expand Down Expand Up @@ -437,7 +408,7 @@ def _requires_no_body?(res)
# @since 2.0.0
# @api private
def enforce_accepted_mime_types(request)
return if config.accepted_formats.empty?
return if config.formats.empty?

Mime.enforce_accept(request, config) { return halt 406 }
Mime.enforce_content_type(request, config) { return halt 415 }
Expand Down
130 changes: 18 additions & 112 deletions lib/hanami/action/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,6 @@ class Action
# @api public
# @since 2.0.0
class Config < Dry::Configurable::Config
# Default MIME type to format mapping
#
# @since 0.2.0
# @api private
DEFAULT_FORMATS = {
"application/octet-stream" => :all,
"*/*" => :all,
"text/html" => :html
}.freeze

# Default public directory
#
# This serves as the root directory for file downloads
Expand Down Expand Up @@ -68,121 +58,37 @@ def handle_exception(exceptions)
.to_h
end

# @!attribute [rw] formats
#
# Specifies the MIME type to format mapping
#
# @return [Hash{String=>Symbol}] MIME type strings as keys and format symbols as values
#
# @see format
# @see Hanami::Action::Mime
# @!attribute [r] formats
# Returns the format config for the action.
#
# @example
# config.formats = {"text/html" => :html}
# @return [Config::Formats]
#
# @since 0.2.0
# @since 2.0.0
# @api public

# Registers a MIME type to format mapping
# Sets the format (or formats) for the action.
#
# @param hash [Hash{Symbol=>String}] format symbols as keys and the MIME
# type strings must as values
#
# @return [void]
#
# @see formats
# @see Hanami::Action::Mime
# To configure custom formats and MIME type mappings, call {Formats#add formats.add} first.
#
# @example
# config.format html: "text/html"
#
# @since 0.2.0
def format(hash)
symbol, mime_type = *Utils::Kernel.Array(hash)
formats[Utils::Kernel.String(mime_type)] = Utils::Kernel.Symbol(symbol)
end

# Returns the configured format for the given MIME type
#
# @param mime_type [#to_s,#to_str] A mime type
#
# @return [Symbol,nil] the corresponding format, nil if not found
#
# @see format
#
# @since 0.2.0
# @api private
def format_for(mime_type)
formats[mime_type]
end

# Returns the configured format's MIME types
#
# @return [Array<String>] the format's MIME types
#
# @see formats=
# @see format
# config.format :html, :json
#
# @since 0.8.0
# @param formats [Array<Symbol>] the format names
#
# @api private
def mime_types
# FIXME: this isn't efficient. speed it up!
((formats.keys - DEFAULT_FORMATS.keys) +
Hanami::Action::Mime::TYPES.values).freeze
end

# Returns a MIME type for the given format
#
# @param format [#to_sym] a format
# @return [Array<Symbol>] the given format names
#
# @return [String,nil] the corresponding MIME type, if present
# @see #formats
#
# @since 0.2.0
# @api private
def mime_type_for(format)
formats.key(format)
end

# @since 2.0.0
# @api private
def accepted_mime_types
accepted_formats.any? ? Mime.restrict_mime_types(self) : mime_types
# @api public
def format(*formats)
if formats.empty?
self.formats.values
else
self.formats.values = formats
end
end

# @!attribute [rw] default_request_format
#
# Sets a format as default fallback for all the requests without a strict
# requirement for the MIME type.
#
# The given format must be coercible to a symbol, and be a valid MIME
# type alias. If it isn't, at runtime the framework will raise an
# `Hanami::Action::UnknownFormatError`.
#
# By default, this value is nil.
#
# @return [Symbol]
#
# @see Hanami::Action::Mime
#
# @since 0.5.0

# @!attribute [rw] default_response_format
#
# Sets a format to be used for all responses regardless of the request
# type.
#
# The given format must be coercible to a symbol, and be a valid MIME
# type alias. If it isn't, at the runtime the framework will raise an
# `Hanami::Action::UnknownFormatError`.
#
# By default, this value is nil.
#
# @return [Symbol]
#
# @see Hanami::Action::Mime
#
# @since 0.5.0

# @!attribute [rw] default_charset
#
# Sets a charset (character set) as default fallback for all the requests
Expand Down
Loading

0 comments on commit fe5a515

Please sign in to comment.