Class: Rack::JSONBodyParser

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/contrib/json_body_parser.rb

Overview

A Rack middleware that makes JSON-encoded request bodies available in the request.params hash. By default it parses POST, PATCH, and PUT requests whose media type is application/json. You can configure it to match any verb or media type via the :verbs and :media options.

Examples:

Parse POST and GET requests only

use Rack::JSONBodyParser, verbs: ['POST', 'GET']

Parse POST|PATCH|PUT requests whose Content-Type matches ‘json’

use Rack::JSONBodyParser, media: /json/

Parse POST requests whose Content-Type is ‘application/json’ or ‘application/vnd+json’

use Rack::JSONBodyParser, verbs: ['POST'], media: ['application/json', 'application/vnd.api+json']

Constant Summary collapse

CONTENT_TYPE_MATCHERS =
{
  String => lambda { |option, header|
    Rack::MediaType.type(header) == option
  },
  Array => lambda { |options, header|
    media_type = Rack::MediaType.type(header)
    options.any? { |opt| media_type == opt }
  },
  Regexp => lambda {
    if //.respond_to?(:match?)
      # Use Ruby's fast regex matcher when available
      ->(option, header) { option.match? header }
    else
      # Fall back to the slower matcher for rubies older than 2.4
      ->(option, header) { option.match header }
    end
  }.call(),
}.freeze
DEFAULT_PARSER =
->(body) { JSON.parse(body, create_additions: false) }

Instance Method Summary collapse

Constructor Details

#initialize(app, verbs: %w[POST PATCH PUT], media: 'application/json', &block) ⇒ JSONBodyParser

Returns a new instance of JSONBodyParser.



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/rack/contrib/json_body_parser.rb', line 45

def initialize(
  app,
  verbs: %w[POST PATCH PUT],
  media: 'application/json',
  &block
)
  @app = app
  @verbs, @media = verbs, media
  @matcher = CONTENT_TYPE_MATCHERS.fetch(@media.class)
  @parser = block || DEFAULT_PARSER
end

Instance Method Details

#call(env) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/rack/contrib/json_body_parser.rb', line 57

def call(env)
  if @verbs.include?(env[Rack::REQUEST_METHOD]) &&
     @matcher.call(@media, env['CONTENT_TYPE'])

    update_form_hash_with_json_body(env)
  end
  @app.call(env)
rescue JSON::ParserError
  body = { error: 'Failed to parse body as JSON' }.to_json
  header = { 'Content-Type' => 'application/json' }
  Rack::Response.new(body, 400, header).finish
end