Gem grape 生成 api 的时候添加返回值的状态字段问题

naitnix · 2012年05月23日 · 最后由 comme 回复于 2012年08月02日 · 4484 次阅读

最近在给 iphone 做接口,用 grape,打算跟 web 项目在同一个项目目录,并打算共用 model,所以选用了 grape,但是涉及到了自定义 json 数据格式的问题,前些天有问群里的大牛们,给出的方法我都试过了,并且读了下 ruby-china 的客户端 api,见到了有类似的写法:

get do
        @topics = Topic.last_actived
          .limit(page_size)
          .includes(:user)
        present @topics, :with => APIEntities::Topic
      end

这其中用到了 APIEntities::Topic,再进入到里面看个究竟,是这样的代码:

module RubyChina
  module APIEntities
    class User < Grape::Entity
      expose :_id, :name, :login, :location, :website, :bio, :tagline, :github_url
      expose(:gravatar_hash) { |model, opts| Digest::MD5.hexdigest(model.email || "") }
      expose(:avatar_url) { |model, opts| model.avatar? ? model.avatar.url(:normal) : "" }
    end

    class Reply < Grape::Entity
      expose :_id, :body, :body_html, :message_id, :created_at, :updated_at
      expose :user, :using => APIEntities::User
    end

    class Topic < Grape::Entity
      expose :_id, :title, :body, :body_html, :created_at, :updated_at, :replied_at, :replies_count, :node_name, :node_id, :last_reply_user_login
      expose :user, :using => APIEntities::User
      # replies only exposed when a single topic is fetched
      expose :replies, :using => APIEntities::Reply, :unless => { :collection => true }
    end

    class Node < Grape::Entity
      expose :_id, :name, :topics_count, :summary, :section_id, :sort
      expose(:section_name) {|model, opts| model.section.name.to_s rescue "" }
    end
  end
end

于是乎,我就照着写了一个类似的

resource :rooms do
      get '/' do
        @rooms = Room.limit 30
        present @rooms, :with => APIEntities::Room
      end
end

以及

module APIEntities
  class Room < Grape::Entity
    expose :id, :title, :custom_num, :home_type
    expose(:address) { |model, opts| model.address_info }
    expose(:price)   { |model, opts| model.price.try(:day_price) }
    expose(:first_screen)   { |model, opts| model.first_screen(:icon) }
  end
end

然后我重启 server 访问: localhost:3000/api/v1/rooms 得到了以下数据:

[
{
home_type: "1",
id: 842,
address: "唐山市xxxxx",
custom_num: 4,
price: 100,
title: "精装单间",
first_screen: "/uploads/screenshot/photo/000/312/icon_aeb963221fb8478e75df3ef480dae4c2.gif"
},
{
id: 843,
home_type: "1",
address: "上海市松江区新桥镇",
custom_num: 4,
price: 100,
title: "精装单间",
first_screen: "/uploads/screenshot/photo/000/307/icon_e3b5c399f052afaed6a14f85eee5ce12.gif"
},
{
home_type: "公寓",
id: 858,
address: "鄂尔多斯市伊金霍洛旗乌兰木伦镇",
custom_num: 1,
price: 100,
title: "精装单间",
first_screen: "/uploads/screenshot/photo/000/000/153/icon_1.jpg"
}
]

这样的数据我基本上是我想要的,因为我都为 room 对象添加了虚拟属性,解决了子父关联关系的问题。但是我还是想加一个 status,标识返回的数据状态,类似与这样:

{"status":"OK",
   {"siteId":"siteId1","siteUrl":"www.site1.300.cn","siteName":"siteName1"},
   {"siteId":"siteId2","siteUrl":"www.site2.300.cn","siteName":"siteName2"}
}

其实就是想在现有的数据的基础上加一个 status,不知道想要得到这样的结果,利用 Grape::Entity 能否实现,昨天我看了看 api 没有找到合适的方法,如果有哪位大牛对 grape 很熟悉的话,希望大家能给个建议,谢谢。

我也想知道。。。。。

给一个思路,建一个虚拟的 Model 和相应的 Entity,Model 中有 status 和 sites 的 attrs。然后 API 里返回这个 Model 的实例(当然你要自己先塞上正确的数据)。

这稍显啰嗦,不过 Grape 确实只支持简单的输出。

找到了一个解决办法: resource :rooms do get '/' do @rooms = Room.select("id,title,custom_num,home_type").order("id desc").limit(10) Jbuilder.encode do |json| json.status 'OK' json.rooms(@rooms) do |json, room| json.id room.id json.title room.title json.custom_num room.custom_num json.home_type room.view_types('home_type') json.price room.price.try(:day_price) json.address room.address_info
json.first_screen room.first_screen(:icon) end end end

在 lib/api.rb 内,调用 jbuilder,在这里生成我想要的 json 格式数据,这个是我觉得目前最好的解决办法了

不过,我感觉可以不用增加 status,如果失败的话,再返回 error 信息。。如果没有 error 肯定就是 OK

@naitnix 改为如下应该就可以了:

resource :rooms do
      get '/' do
        @rooms = Room.limit 30
        present @rooms, :with => APIEntities::Room
        body( { status: "OK", data: body() )
      end
end

不过跟你要求的格式还是有区别的

需要 登录 后方可回复, 如果你还没有账号请 注册新账号