Reputation: 29004
A Rails application with a RESTful interface needs to accept POST data using a custom MIME type based on 'application/json'. Let's call that MIME type 'application/vnd.com.example.Foo+json'.
Registering the custom MIME type in Rails using Mime::Type.register works fine in that the application recognizes the MIME type given in the "Accept:" header and renders a JSON view through respond_to.
The problem is with controller methods such as update and create that need to convert custom JSON formatted data into a params hash. If I set the "Content Type:" header to application/json, the data gets parsed into the params hash.
But if I set the "Content Type:" header to 'applcation/vnd.com.example.Foo+json', then the payload does not get parsed.
So it seems like MIME::Type.register is used for driving the respond_to block, but not in deciding how to parse payloads for create and update methods.
Any ideas?
Upvotes: 8
Views: 4245
Reputation: 71
Here's what I learned working with this in Rails 5:
Rich's information was a great starting point and, like him, I added my code in an initializer (in config/initializers/mime_types.rb
).
In my scenario, when working with a custom content type that can be parsed as regular json, it's simple to add another synonym to the json mime type like this:
json_mime_type_synonyms = %w[
text/x-json
application/jsonrequest
application/foobar+json
]
Mime::Type.register('application/json', :json, json_mime_type_synonyms)
If you take that approach, be sure to include the other synonyms (they're from the default json mime type) to ensure they continue to work properly.
Alternatively, if you need custom parsing logic or prefer separate mime types, here is how to both register the mime type and its associated parameter parser:
Mime::Type.register('application/foobar+json', :foobar_json)
ActionDispatch::Request.parameter_parsers[:foobar_json] = -> (body) {
JSON.parse(body)
}
Upvotes: 2
Reputation: 107718
In Rails 5 do:
ActionDispatch::Request.parameter_parsers[Mime::Type.lookup('application/vnd.api+json').symbol] = lambda do |body|
JSON.parse(body)
end
Upvotes: 5
Reputation: 465
In Rails 3 do:
ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime::Type.lookup('application/vnd.com.example.foo+json')]=lambda do |body|
JSON.parse(body)
end
Upvotes: 4
Reputation: 29004
For those who may be interested, I found the answer to my own question.
Use something like this in mime_types.rb (or possibly elsewhere in your your initialization sequence):
ActionController::Base.param_parsers[Mime::Type.lookup('application/vnd.com.example.foo+json')]=lambda do |body|
JSON.parse body
end
One catch: don't use capitalization in the MIME type above (i.e., 'application/vnd.com.example.Foo+json'). Rails converts the MIME type into all lower case, so no match will be found it it's set to upper case.
Upvotes: 6