我有一个 Grape::API
的小型原型(prototype)子类作为机架服务,并且正在使用 Grape::Entity
来呈现我的应用程序的内部对象。
我喜欢 Grape::Entity
DSL,但我很难找到我应该如何超越默认的 JSON 表示,这对我们的目的来说太轻了。我被要求以“jsend 或类似”格式生成输出:http://labs.omniti.com/labs/jsend
我完全不确定什么性质的变化最符合 Grape 框架(我想要一条阻力最小的路径)。我应该创建一个自定义的 Grape 格式化程序(我不知道该怎么做),新的机架中间件(我已经这样做是为了通过 SysLog 记录 API 输入/输出 - 但格式看起来很糟糕,因为我需要从 JSON 解析主体以添加容器级别),或者从 Grape::Entity
更改为例如拉 bool ?
示例代码(“app.rb”)
require "grape"
require "grape-entity"
class Thing
def initialize llama_name
@llama_name = llama_name
end
attr_reader :llama_name
end
class ThingPresenter < Grape::Entity
expose :llama_name
end
class MainService < Grape::API
prefix 'api'
version 'v2'
format :json
rescue_from :all
resource :thing do
get do
thing = Thing.new 'Henry'
present thing, :with => ThingPresenter
end
end
end
机架文件(“config.ru”)
require File.join(File.dirname(__FILE__), "app")
run MainService
我启动它:
rackup -p 8090
并称它为:
curl http://127.0.0.1:8090/api/v2/thing
{"llama_name":"Henry"}
我想看到的:
curl http://127.0.0.1:8090/api/v2/thing
{"status":"success","data":{"llama_name":"Henry"}}
显然我可以做类似的事情
resource :thing do
get do
thing = Thing.new 'Henry'
{ :status => "success", :data => present( thing, :with => ThingPresenter ) }
end
end
在每条路线上——但那似乎不是很干燥。当这个 API 变得更大并由整个团队维护时,我正在寻找更干净的东西,并且不太容易出现剪切和粘贴错误
奇怪的是,当我尝试 { :status => "success", :data => present( thing, :with => ThingPresenter ) }
使用 grape 0.3.2
,我无法让它工作。 API 仅从 present
返回值 - 这里发生的事情比我最初想象的要多。
最佳答案
这就是我通过阅读 Grape 文档、谷歌搜索和阅读 github 上的一些拉取请求的组合而得到的结果。基本上,在声明 :json
格式(以获取它附带的所有其他默认好东西)之后,我用添加 jsend 包装层的新格式覆盖输出格式化程序。这比尝试包装 Grape 的 #present
帮助程序(不能很好地覆盖错误)或机架中间件解决方案(需要反序列化和重新序列化 JSON,加上需要大量额外的代码来弥补错误)。
require "grape"
require "grape-entity"
require "json"
module JSendSuccessFormatter
def self.call object, env
{ :status => 'success', :data => object }.to_json
end
end
module JSendErrorFormatter
def self.call message, backtrace, options, env
# This uses convention that a error! with a Hash param is a jsend "fail", otherwise we present an "error"
if message.is_a?(Hash)
{ :status => 'fail', :data => message }.to_json
else
{ :status => 'error', :message => message }.to_json
end
end
end
class Thing
def initialize llama_name
@llama_name = llama_name
end
attr_reader :llama_name
end
class ThingPresenter < Grape::Entity
expose :llama_name
end
class MainService < Grape::API
prefix 'api'
version 'v2'
format :json
rescue_from :all
formatter :json, JSendSuccessFormatter
error_formatter :json, JSendErrorFormatter
resource :thing do
get do
thing = Thing.new 'Henry'
present thing, :with => ThingPresenter
end
end
resource :borked do
get do
error! "You broke it! Yes, you!", 403
end
end
end
关于Ruby Grape JSON-over-HTTP API,自定义 JSON 表示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15498093/