Rack middleware for parsing incoming request body per content type.
Rack::BodyParser is heavily inspired by
Rack::Parser,
but behaves a bit different. See Key Features.
Rack::BodyParseronly parses the request body.Rack::BodyParserdoes not touch or replace the originalparamsorrequest.params, and does not mixparamsand body payload. Instead the parsed result is stored in a separate keyparsed_bodyin Rack'senv.(optional) patching of
Rack::Requestwith support for custom getter method Parsed result available asrequest.parsed_bodywith support for customrequest.#{your_key_here}per parser. Enable with:patch_request => true.(optional) access to headers/env. If your parser
respond_to? :env=, this setter method will be invoked with Rack'senvjust before runningcallon your parser.
Rack::BodyParserdoesnot contain any parsers out of the box.
Available through RubyGems:
gem install rack-bodyparser
Define your :parsers per media-type, which is the content-type without media type parameters;
e.g., when content-type is text/plain;charset=utf-8, the media-type is text/plain.
Parsers configuration accepts a String or Regexp as media-type key,
and anything that respond_to? 'call' as parser.
Sinatra example:
# app.rbuseRack::BodyParser,:parsers=>{'application/json'=>proc{ |data| JSON.parsedata},'application/xml'=>proc{ |data| XML.parsedata},/msgpack/=>proc{ |data| Msgpack.parsedata}}post'/'doputsenv['parsed_body']endRack::BodyParser has one default error handler that can be overridden by
setting the 'default' handler. As with parsers, you can use a String or
Regexp as media-type key and anything that respond_to? 'call' as the
error handler. The error handler must accept the two parameters
Error and type (the media type).
useRack::Parser,:handlers=>{'default'=>proc{ |e,type| [400,{},['[Rack::BodyParser] Failed to parse %s: %s' % [type,e.to_s]]]},'application/xml'=>proc{[400,{},'Error: XML unsupported']}}Note: the error handler rescues exceptions that descend from StandardError.
See http://www.mikeperham.com/2012/03/03/the-perils-of-rescue-exception/
Rack::BodyParser will try to warn if a logger is present.
Setting up Rack::BodyParser with :patch_request => true will add
a parsed_body getter method to Rack::Request. Parsers can also provide a
:rack_request_key to define a custom key per parser:
# gem 'jsonapi_parser'require'json/api'# JSONAPI document parser/validatormoduleRack::BodyParser::JSONAPImoduleParser# This defines the getter key for Rack::Requestdefself.rack_request_key;:document;enddefself.call(body)JSON::API.parse(JSON.parse(body))endendmoduleErrordefself.call(e,type)payload={errors: {title: 'Failed to parse body as JSONAPI document',detail: e.message}}.to_json[422,{},[payload]]endendenduseRack::BodyParser,:patch_request=>true,:parsers=>{'application/vnd.api+json'=>Rack::BodyParser::JSONAPI::Parser},:handlers=>{'application/vnd.api+json'=>Rack::BodyParser::JSONAPI::Error}post'/'do# These all output the sameputsenv['parsed_body']putsrequest.parsed_bodyputsrequest.documentendNeed headers or other data from Rack's env in your parser? Set up your parser
with a setter method, respond_to? :env=, and it will be invoked just before running
the main call method.
moduleThisParserNeedsHeadersdefself.env=(env)@env=envenddefself.call(body)# @env available here for your parsing pleasure.endenduseRack::BodyParser,:parsers=>{'plain/text'=>ThisParserNeedsHeaders}Copyright © 2016, 2017 Aaron Heesakkers.
See MIT-LICENSE for details.