Gem grape 做 api 的时候能不能定制 json 数据格式

naitnix · 2012年05月18日 · 最后由 birbird 回复于 2015年08月01日 · 4264 次阅读

最近在给网站做一个客户端,需要返回给客户端的数据类型为 json 格式,json 数据的格式如下:

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

我的 api 里面是这样写的:

class API  < Grape::API
   prefix "api"
   version 'v1'
   format :json
   default_format :json

   resource :users do

     get do
       @users = User.all
     end

     get ":id" do
       @user = User.find(params[:id])
     end

     post do
       @user = User.new(:username => params[:username],:mobile => params[:mobile])
     end

   end
 end

在我请求地址:localhost:3000/api/v1/users 的时候要返回所有的用户信息,但是这个时候的返回数据格式是这样的:

[
{
id: 1,
username: "naitnix",
mobile: "15210427877",
role: "owner"
},
{
id: 1,
username: "naitnix",
mobile: "1521xxxxxxxx",
role: "owner"
},
{
id: 1,
username: "naitnix",
mobile: "1521xxxxxxxx",
role: "owner"
}
]

这个格式不是我想要的,所以我想要定制我自己的 json 数据格式,这个不知道有没有什么好的办法能解决这个问题,望各位指点迷津。

我用 Hashie 来包装数据结构

resource "products" do

  desc "返回所有产品列表"
  get do
     m = Hashie::Mash.new
     m.code = 0
     m.message = ""
     md = []

     begin
       Product.all.each do |product|
         md << product
       end
     rescue => e
       m.code = 1
       m.message = "#{e}"
     end

     m.data = md
     m.to_json
  end

输出:

{
 "code":0,
 "message":"",
 "data":[
     {
      "created_at":"2012-05-08T20:54:06+08:00",
      "deploy_path":"xxxx",
      "description":"xxxx",
      "id":1,
      "name":"xxx",
      "package_name":"xxx",
      "updated_at":"2012-05-08T21:16:05+08:00"
     },
     {
      "created_at":"2012-05-08T21:15:21+08:00",
      "deploy_path":"xxx",
      "description":"xxx",
      "id":2,
      "name":"xxx",
      "package_name":"xxx",
      "updated_at":"2012-05-08T21:15:21+08:00"
     }
 ]
}

如果这样的话,感觉效率太低了,每次一个查询过来的话,我都要循环一次,然后格式化成一个新的 json,感觉这样的处理不好

#2 楼 @naitnix 其实 #1 楼 @suupic 的方法是对的,只要 get do ... end 中最后一行返回的是一个 json 或者 array / hash (会被自动调用 to_json 方法) 既可,而且每次一个查询过来都需要循环一次的做法也是对的,你可以不用 Hashie 但是从 DB 中 load 数据 和 循环你无法避免,建议在一楼答案的基础上,将生成 json 的方法移到 Model 中,然后用 Redis 或者 Memcached 将生成的 JSON 作缓存,只要处理得当,效率的问题可以通过 Cache 解决。

其实我自己是用 rabl 来解决这个问题的。

建议你看一下。rabl 类似一个 haml/slim 模板,虽然最终也是循环。但是结果可定义,而且比这个方法简单好看很多。

ps: DHH 写的 jbuilder 也是解决这个问题的。( 不是 Java 那个 JBuilder.

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