Ruby Grape JSON-over-HTTP API,自定义JSON表示

Nei*_*ter 10 ruby ruby-grape jsend

我有一个小型的原型子类Grape::API作为机架服务,并Grape::Entity用于呈现我的应用程序的内部对象.

我喜欢Grape::EntityDSL,但我很难找到我应该超越默认的JSON表示,这对我们来说太轻了.我被要求以"jsend或类似"格式生成输出:http://labs.omniti.com/labs/jsend

我完全不确定改变的性质与Grape框架最相符(我想在这里采用最小阻力路径).我应该创建一个自定义的Grape格式化程序(我不知道如何做到这一点),新的机架中间件(我这样做是为了通过SysLog记录API输入/输出 - 但格式化似乎很糟糕,因为我需要解析正文从JSON返回以添加容器级别),或者更改Grape::Entity为例如RABL?

示例代码("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
Run Code Online (Sandbox Code Playgroud)

Rackup文件("config.ru")

require File.join(File.dirname(__FILE__), "app")
run MainService
Run Code Online (Sandbox Code Playgroud)

我启动它:

rackup -p 8090
Run Code Online (Sandbox Code Playgroud)

并称之为:

curl http://127.0.0.1:8090/api/v2/thing
{"llama_name":"Henry"}
Run Code Online (Sandbox Code Playgroud)

我想看到的:

curl http://127.0.0.1:8090/api/v2/thing
{"status":"success","data":{"llama_name":"Henry"}}
Run Code Online (Sandbox Code Playgroud)

显然我可以做类似的事情

  resource :thing do
    get do
      thing = Thing.new 'Henry'
      { :status => "success", :data => present( thing, :with => ThingPresenter ) }
    end
  end
Run Code Online (Sandbox Code Playgroud)

在每条路线 - 但这似乎不是很干.我正在寻找更清洁的东西,并且当这个API变得更大并且由整个团队维护时,更不容易削减和粘贴错误


奇怪的是,当我尝试{ :status => "success", :data => present( thing, :with => ThingPresenter ) }使用时grape 0.3.2,我无法让它工作.API返回的值只是present- 这里的内容比我最初想的要多.

Nei*_*ter 15

这是我最终得到的,通过阅读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
Run Code Online (Sandbox Code Playgroud)