2

I've built a rails API that receives JSON. I want to validate that the request body is valid JSON and provide a valid error on the API response if not. Spent quite a lot of time trying different options and trying to find an answer but no success.

Whatever I do to try and catch the error, it always throws the following error when I send some incorrect test JSON.

JSON::ParserError at /api/v1/apikey123

743: unexpected token at '{
    "query": "hi there" (missing comma here on purpose)
    "lang": "en",
    "sessionId": "en" }

json (2.0.2) lib/json/common.rb, line 156

``` ruby
151     #   additions even if a matching class and create_id was found. This option
152     #   defaults to false.
153     # * *object_class*: Defaults to Hash
154     # * *array_class*: Defaults to Array
155     def parse(source, opts = {})
> 156       Parser.new(source, opts).parse  
157     end
158   
159     # Parse the JSON document _source_ into a Ruby data structure and return it.
160     # The bang version of the parse method defaults to the more dangerous values
161     # for the _opts_ hash, so be sure only to parse trusted _source_ documents.

Here is my code:

module Api
  class ApiController < ApplicationController
    protect_from_forgery with: :null_session
    before_action :authenticate, :parse_request

    private
    def parse_request
      begin
        @user_input = JSON.parse(request.body.read)
      rescue JSON::ParserError => e
         return false
      end
    end

    ...

  end
end

I'd like to know how to handle this without throwing an error and send back a response that has an error message with "Invalid JSON format"

1
  • I've just found that if I remove the Content-Type: application/json from the request headers, it works perfectly!! It seems that this is being called from somewhere else... is this normal Rails behaviour? Commented Dec 16, 2016 at 16:01

1 Answer 1

1

You should just call render method in your rescue block. The action method will be halted because you call render.

def parse_request
  begin
    @user_input = JSON.parse(request.body.read)
  rescue JSON::ParserError => e
    render json: {error: "Invalid JSON format"}, status: :unprocessable_entity
  end
end
Sign up to request clarification or add additional context in comments.

8 Comments

Nice idea! However, I still get the above error before it gets to the rescue line :-(
I've just found that if I remove the Content-Type: application/json from the request headers, it works perfectly!! It seems that this is being called from somewhere else... is this normal Rails behaviour?
If you send a request with json content-type then Rails middleware will parse it before to pass it in controller. So, when you remove content-type Rails will not be parse body to json. You should read this article about catching json errors robots.thoughtbot.com/…
I'm not sure but you can try to use rescue_from JSON::ParserError in controller.
This middleware is missed in Rails 5. You should another. Run rake middleware to list all. Probably you need to use Rack::Head
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.