Wants

This library provides support for choosing the proper MIME type for a response.

Installation

With Rubygems:

gem install wants

With Bundler:

gem 'wants'

Loading

Simply require the gem name:

require 'wants'

Usage

Wants.new

wants = Wants.new( accept, [ :html, :json, :atom ] )

The Wants constructor takes two arguments:

  • The value of an HTTP Accept header. cf RFC 2616, ยง14.1
  • an Array of all the supported MIME types, each of which can be a full type (e.g. "application/json") or, if Rack is loaded, a key in Rack::Mime::MIME_TYPES. (If you want to use a different lookup table, you can set Wants.mime_lookup_table.)

Wants.new will return to you a Wants::MatchResult object that represents the single best MIME type from the available options. It supports a variety of introspection methods:

MatchResult#not_acceptable?

This predicate tell you whether there was no acceptable match. For example,

wants = Wants.new( { 'application/json' }, [ :html ] )
wants.not_acceptable? # true

This method is aliased as #blank? and its inverse is available as #present?.

MatchResult#{mime}?

You can use a MIME abbreviation as a query method on the matcher. For example,

acceptable = 'text/html,application/xhtml+xml;q=0.9'
offered = [ :html, :json ]
wants = Wants.new( acceptable, offered )
wants.html?  # true
wants.xhtml? # false
wants.json?  # false

MatchResult#[{mime}]

To query a full MIME type, use #[]. For example,

acceptable = 'text/html,application/xhtml+xml;q=0.9'
offered = [ :html, :json ]
wants = Wants.new( acceptable, offered )
wants[:html]                    # true
wants['text/html']              # true
wants['application/xhtml_xml']  # false
wants['application/json']       # false

MatchResult#{mime}

Lastly, you can use the matcher as DSL. For example,

acceptable = 'application/json,application/javascript;q=0.8'
offered = [ :html, :json ]
wants = Wants.new( acceptable, offered )

wants.atom           { build_an_atom_response }
wants.json           { build_a_json_response }
wants.html           { build_an_html_response }
wants.not_acceptable { build_a_406_unacceptable_response }
wants.any            { build_a_generic_response }

In this example, only build_a_json_response will be evaluated. wants.json and all subsequent wants.{mime} calls, including wants.not_acceptable and wants.any, will return whatever build_a_json_response returned. More formally, each wants.{mime} call behaves as follows:

  1. if @response_value is not nil, return it
  2. if [method name] is the abbreviation for the desired MIME type, evaluate the block and set the result to @response_value

wants.not_acceptable will match if wants.not_acceptable? returns true. wants.any will match if wants.not_acceptable? returns false. Thus, wants.any should be placed after all other matchers.

Wants::ValidateAcceptsMiddleware

Usage in config.ru:

require 'wants/validate_accepts_middleware'

use Wants::ValidateAcceptsMiddleware, :mime_types => [ :html, :json ]
run MyApp

This will pass HTML and JSON requests down to MyApp and return a 406 Not Acceptable response for all others. You can configure the failure case with the :on_not_acceptable option:

use Wants::ValidateAcceptsMiddleware,
  :mime_types => [ ... ],
  :on_not_acceptable => lambda { |env| ... }