0

I have a Granite User model with some validations. When someone makes a POST request to users/new, I'd like to return the validation errors (if any) as JSON. Currently, I have:

if user.errors.size > 0
  halt env, status_code: 500, response: user.errors.to_json
end

But when I try to compile, I get:

in /usr/local/Cellar/crystal/0.26.1/src/json/to_json.cr:66: no overload 
matches 'Granite::Error#to_json' with type JSON::Builder
Overloads are:
- Object#to_json(io : IO)
- Object#to_json()

  each &.to_json(json)
         ^~~~~~~
Hyrum Carlile
  • 107
  • 3
  • 7

1 Answers1

1

So the issue is that User#errors is an Array(Granite::Error), i.e. an Array holding Granite::Errors. Unfortunately, it doesn't look like Granite::Error implements the to_json(JSON::Builder) method (i.e. the method to_json taking a parameter of type JSON::Builder), which Array#to_json relies on (that snippet you see there is from the implementation of Array#to_json which you can view on GitHub.).

I'd recommend building the JSON yourself using JSON.build. This has the added side-effect of keeping the JSON that you respond with (which I imagine is being consumed by some client) is entirely in your control. If the developers of Granite were to change how they encode Granite::Errors in JSON and you were using their to_json method, the change wouldn't raise anything at compile time.

As a side-note, I'd recommend against using a status code of 500 to denote a validation error, as that is typically reserved for unexpected errors internal to your server. A 4xx error (e.g. 400 - Bad Request) would be more appropriate. As a second side-note, it would be more RESTful to have the POST be made to the /users endpoint, as opposed to /users/new.

With these changes, here would be the resulting snippet:

if user.errors.size > 0
  errors_as_json = JSON.build do |json|
    json.array do
      user.errors.each do |error|
        json.string error.to_s
      end
    end
  end
  halt env, status_code: 400, response: errors_as_json
end
pixatlazaki
  • 572
  • 8
  • 19
  • Thanks for your help! I haven't had time to work on that project in a little while. Once I do, if your solution works, I'll accept it as the answer. – Hyrum Carlile Sep 22 '18 at 19:12