将Granite验证错误返回为JSON

时间:2018-09-11 11:45:47

标签: crystal-lang kemal

我有一个经过验证的Granite User模型。当有人向POST发出users/new请求时,我想以JSON形式返回验证错误(如果有)。目前,我有:

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

但是当我尝试编译时,我得到了:

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)
         ^~~~~~~

1 个答案:

答案 0 :(得分:1)

因此,问题在于User#errorsArray(Granite::Error),即Array持有Granite::Error个。不幸的是,Granite::Error似乎并没有实现to_json(JSON::Builder)所依赖的to_json方法(即方法JSON::Builder采用类型为Array#to_json的参数) (您看到的摘录来自Array#to_json的实现,您可以view on GitHub来实现。)

我建议您自己使用JSON.build构建JSON。这具有使您响应的JSON(我想它已被某些客户端使用)完全由控制的副作用。如果Granite的开发人员要更改他们在JSON中编码Granite::Error的方式,而您使用的是to_json方法,则此更改在编译时不会产生任何作用。

作为旁注,我建议不要使用状态码500表示验证错误,因为通常将其保留给服务器内部的意外错误。 4xx错误(例如400-错误的请求)会更合适。作为第二个补充说明,将POST设置为/users端点而不是/users/new会更令人放松。

进行了这些更改后,将生成以下代码段:

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