使用Jbuilder(或其他)Rails JSON API布局
在我的rails 3.2应用程序中,我使用jbuilder来呈现来自我的JSON api的响应。
我想为所有API响应提供一个通用结构,并且布局可能是保持我的视图DRY的可能解决方案。
例如:我希望每个回复都是以下forms:
{ status: "ok|error|redirect", data: { ... JSON specific to the current view ... }, errors: [ ... ], notes: [ ... ] }
(其中数据的值是视图提供的json结构,其他所有内容都来自布局)
但是:我无法让jbuilder布局正确地产生视图。
# in layout json.data yield # in view json.some "value"
结果是:
{"data":"{\"some\":\"value\"}"} # arg! my json has become a string
以另一种方式尝试:
# in layout yield # in view json.data do |json| json.some "value" end
结果是 :
{}
有没有人用jbuilder或其他json模板gem /方法做到这一点?
这个juilder github问题表明它是可能的,但表明其他人也有类似的问题。
我看到rabl(https://github.com/nesquena/rabl/)应该支持布局(https://github.com/nesquena/rabl/wiki/Using-Layouts),但我决定不使用由于其他原因(rabl使复杂的json结构成为一场噩梦,特别是在试图控制对象根等时)。
你可以通过这种方式做到这一点
# api.v1.json.jbuilder - layout json.request do json.message "your message" json.status 200 end json.data JSON.parse(yield) # show.json.jbuilder - action view json.name 'Some item name'
我会根据我们提出的解决方案为您提供替代方案:
# app/helpers/application_helper.rb module ApplicationHelper def envelope(json, status, errors, notes) json.status status json.data do yield if block_given? end json.errors errors json.notes notes end end
然后,在视图中,您可以调用信封并包含您的json代码,如:
# app/views/api/v1/test/show.json.jbuilder envelope(json, "OK" ) do json.some 'value' end
迟到的答案,但帮助我得到了我想要的…
成功结果:
{ "something": {"id": 42, "message": "hello"}, "status": "ok", "errors": [] }
错误结果:
{ "something": null, "status": "error", "errors": ["could not do the thing"] }
码:
应用程序/控制器/ API / V1 / base_controller.rb
class Api::V1::BaseController < ActionController::API layout 'api/v1/application' before_action :setup_layout_elements def setup_layout_elements @status = :ok @errors = [] end def error!(message) @status = :error @errors << message nil end end
应用程序/控制器/ API / V1 / some_controller.rb
class Api::V1::SomeController < Api::V1::BaseController def index @something = begin possibly_error_causing_code rescue error!('could not do the thing') end render builder: 'api/v1/something/index' end end
应用程序/视图/布局/ API / V1 / application.json.jbuilder
json.merge! JSON.parse(yield) json.status @status json.errors @errors
应用程序/视图/ API / V1 /事/ index.json.jbuilder
json.something do json.id @something.id json.message @something.to_s end
如果您不想包含额外的密钥,您可以这样做
class UsersController < ApplicationController layout: 'json_layout' end
在/app/views/layouts/json_layout.json.jbuilder中
json.success true r = JSON.parse(yield) r.each{|k,v| json.set! k,v }
JBuilder不支持使用json.jbuilder
作为您的布局(请参阅Github上的问题#172 )。
我设法避免使用json.erb
作为我的布局格式进行额外的parse
和generate
。
应用程序/控制器/ API / base_controller.rb:
class Api::BaseController < ActionController::Base layout "api.v1" end
应用程序/视图/布局/ api.v1.json.erb:
{ <% if @api_errors.present? %> "errors": <%= raw JSON.dump @api_errors %>, <% else %> "data": <%= yield %>, <% end %> "meta": <%= raw JSON.dump @api_meta %> }
jbuilder是非常简单的API视图技术,你可以在这里添加部分内容,所以如果你想为所有API创建一个装饰器或为公共响应创建部分响应,并在任何需要的地方调用响应
让我们说如果你想
{ status: "ok|error|redirect", data: { ... JSON specific to the current view ... }, errors: [ ... ], notes: [ ... ] }
为此/ views / api / common / _some_partial创建一个部分
json.status "ok whatever the message" json.data do json.message "message" end json.errors @errors json.notes @notes_array
它为您的问题提供了非常简单的解决方案
干杯