I am using Rails 5 and I am trying to improve error handling for invalid JSON requests to my API.
I tried handling invalid format JSON by parsing in the controller with a rescue but realised that Rails middleware is parsing my JSON request before it hits the controller if a user adds Content Type to their request header.
I followed the below guide: https://robots.thoughtbot.com/catching-json-parse-errors-with-custom-middleware
However, I get the following error when starting the server:
.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/stack.rb:108:in `assert_index': No such middleware to insert before: ActionDispatch::ParamsParser (RuntimeError)
Now, what this means is that ActionDispatch::ParamsParser isn't running. I think that it is deprecated in Rails 5 so that rules out that option.
I also tried to use rescue_from in my API Controller:
rescue_from JSON::ParserError, with: :json_error
def json_error
render status: 400, json: {error: "Invalid JSON format in request body"}, status: :unprocessable_entity
end
However, this also did not work. It seems to skip past it.
Or if I try this:
rescue_from JSON::ParserError, with: json_error
def json_error
render status: 400, json: {error: "Invalid JSON format in request body"}, status: :unprocessable_entity
end
I get:
undefined local variable or method `json_error' for Api::ApiController:Class
actionpack (5.0.0.1) lib/action_dispatch/routing/route_set.rb, line 46
``` ruby
41 private
42
43 def controller(req)
44 req.controller_class
45 rescue NameError => e
> 46 raise ActionController::RoutingError, e.message, e.backtrace
47 end
48
49 def dispatch(controller, action, req, res)
50 controller.dispatch(action, req, res)
51 end
Getting very lost, could use some guidance
Seems the guide above is outdated with Rails 5. After some investigation, it seems that the following middleware is no longer called:
config/application.rb
config.middleware.insert_before ActionDispatch::ParamsParser, "CatchJsonParseErrors"
I modified it to be:
require "./lib/middleware/catch_json_parse_errors.rb"
config.middleware.insert_before Rack::Head, CatchJsonParseErrors
This is because Rack::Head is in the middleware stack, but ActionDispatch::ParamsParser is not. Also, the use of Class names as strings is deprecated, so you need to require the file and then pass in the class.
I also modified the below class to check env['CONTENT_TYPE'] instead of env['HTTP_ACCEPT']
class CatchJsonParseErrors
def initialize(app)
@app = app
end
def call(env)
begin
@app.call(env)
rescue ActionDispatch::ParamsParser::ParseError => error
if env['CONTENT_TYPE'] =~ /application\/json/
error_output = "There was a problem in the JSON you submitted: #{error.class}"
return [
400, { "Content-Type" => "application/json" },
[ { status: 400, error: error_output }.to_json ]
]
else
raise error
end
end
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With