Module: Roda::RodaPlugins::TypeRouting
- Defined in:
- lib/roda/plugins/type_routing.rb
Overview
This plugin makes it easier to to respond to specific request data types. User agents can request
specific data types by either supplying an appropriate Accept request header
or by appending it as file extension to the path.
Example:
plugin :type_routing
route do |r|
r.get 'a' do
r.html{ "<h1>This is the HTML response</h1>" }
r.json{ '{"json": "ok"}' }
r.xml{ "<root>This is the XML response</root>" }
"Unsupported data type"
end
end
This application will handle the following paths:
- /a.html
HTML response
- /a.json
JSON response
- /a.xml
XML response
- /a
HTML, JSON, or XML response, depending on the Accept header
The response Content-Type header will be set to a suitable value when
the r.html, r.json, or r.xml block is matched.
Note that if no match is found, code will continue to execute, which can result in unexpected behaviour. This should only happen if you do not handle all supported/configured types. If you want to simplify handling, you can just place the html handling after the other types, without using a separate block:
route do |r|
r.get 'a' do
r.json{ '{"json": "ok"}' }
r.xml{ "<root>This is the XML response</root>" }
"<h1>This is the HTML response</h1>"
end
end
This works correctly because Roda's default Content-Type is text/html. Note that
if you use this approach, the type_routing plugin's :html content type will not be
used for html responses, since you aren't using an r.html block. Instead, the
Content-Type header will be set to Roda's default (which you can override via
the default_headers plugin).
If the type routing is based on the Accept request header and not the file extension,
then an appropriate Vary header will be set or appended to, so that HTTP caches do
not serve the same result for requests with different Accept headers.
To match custom extensions, use the :types option:
plugin :type_routing, types: {
yaml: 'application/x-yaml',
js: 'application/javascript; charset=utf-8'
}
route do |r|
r.get 'a' do
r.yaml{ YAML.dump "YAML data" }
r.js{ "JavaScript code" }
# or:
r.on_type(:js){ "JavaScript code" }
"Unsupported data type"
end
end
Plugin options
The following plugin options are supported:
:default_type :: The default data type to assume if the client did not
provide one. Defaults to :html.
:exclude :: Exclude one or more types from the default set (default set
is :html, :xml, :json).
:types :: Mapping from a data type to its MIME-Type. Used both to match
incoming requests and to provide Content-Type values. If the
value is nil, no Content-Type will be set. The type may
contain media type parameters, which will be sent to the client
but ignored for request matching.
:use_extension :: Whether to take the path extension into account.
Default is true.
:use_header :: Whether to take the Accept header into account.
Default is true.
Defined Under Namespace
Modules: RequestMethods
Constant Summary collapse
- REQUEST_INSTANCE_VARIABLES =
[:@requested_type, :@type_routing_extension].freeze
- CONFIGURATION =
{ :mimes => { 'text/json' => :json, 'application/json' => :json, 'text/xml' => :xml, 'application/xml' => :xml, 'text/html' => :html, }.freeze, :types => { :json => 'application/json'.freeze, :xml => 'application/xml'.freeze, :html => 'text/html'.freeze, }.freeze, :use_extension => true, :use_header => true, :default_type => :html }.freeze
Class Method Summary collapse
Class Method Details
.configure(app, opts = {}) ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/roda/plugins/type_routing.rb', line 112 def self.configure(app, opts = {}) config = (app.opts[:type_routing] || CONFIGURATION).dup [:use_extension, :use_header, :default_type].each do |key| config[key] = opts[key] if opts.has_key?(key) end types = config[:types] = config[:types].dup mimes = config[:mimes] = config[:mimes].dup Array(opts[:exclude]).each do |type| types.delete(type) mimes.reject!{|_, v| v == type} end if mapping = opts[:types] types.merge!(mapping) mapping.each do |k, v| if v mimes[v.split(';', 2).first] = k end end end types.freeze mimes.freeze type_keys = config[:types].keys config[:extension_regexp] = /(.*?)\.(#{Regexp.union(type_keys.map(&:to_s))})\z/ type_keys.each do |type| app::RodaRequest.send(:define_method, type) do |&block| on_type(type, &block) end app::RodaRequest.send(:alias_method, type, type) end app.opts[:type_routing] = config.freeze end |