AU : I sent invalid JSON payload and in return I did not get valid JSON response. My mobile application crashed because I was expecting response to be valid JSON.
AB : Do you know how Rails parses JSON data.
AU : Nope.
AB : The thing is that if the payload is invalid JSON then the request does not even hit the controller.
AB : Rails attempts to parse the payload and since the paylaod is invalid it blows up up in the middleware stack.
AU : I see.
AU : Well we can write a custom middleware which will catch the exception and will return a valid JSON data.
AB : I have no idea how to do that.
AU : Ok. Here is my attempt to build it.
1# app/middleware/catch_json_parse_errors.rb
2
3class CatchJsonParseErrors
4
5 def initialize app
6 @app = app
7 end
8
9 def call env
10 begin
11 @app.call(env)
12 rescue ActionDispatch::ParamsParser::ParseError => exception
13 content_type_is_json?(env) ? build_response(exception) : raise(exception)
14 end
15 end
16
17 private
18
19 def content_type_is_json? env
20 env['CONTENT_TYPE'] =~ /application\/json/
21 end
22
23 def error_message exception
24 "Payload data is not valid JSON. Error message: #{exception}"
25 end
26
27 def build_response exception
28 [ 400, { "Content-Type" => "application/json" }, [ { error: error_message(exception) }.to_json ] ]
29 end
30
31end
AU : Now we need to use this middleware. Here is how we can ask Rails to use this custom middleware.
1# config/application.rb
2
3require File.expand_path('../boot', __FILE__)
4require 'rails/all'
5Bundler.require(:default, Rails.env)
6
7module Wheel
8 class Application < Rails::Application
9 config.middleware.insert_before ActionDispatch::ParamsParser,
10 "CatchJsonParseErrors"
11 end
12end