首页 > 解决方案 > 以 JSON 形式返回 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)
         ^~~~~~~

标签: crystal-langkemal

解决方案


所以问题是那User#errors是一个Array(Granite::Error),即一个Array控股Granite::Errors。不幸的是,它看起来不像Granite::Error实现了to_json(JSON::Builder)方法(即采用to_jsontype 参数的方法JSON::Builder),它Array#to_json依赖于(你看到的那个片段来自Array#to_json你可以在 GitHub 上查看的实现。)。

我建议自己使用JSON.build. 这具有额外的副作用,即保持您响应的 JSON(我想它正在被某些客户端使用)完全在您的控制之中。如果 Granite 的开发人员要更改他们Granite::Error在 JSON 中编码 s 的方式并且您正在使用他们的to_json方法,那么更改不会在编译时引发任何问题。

作为旁注,我建议不要使用状态码 500 来表示验证错误,因为这通常是为服务器内部的意外错误保留的。4xx 错误(例如 400 - Bad Request)会更合适。作为第二个旁注,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

推荐阅读