我期望返回以下格式的数据:
{
code: 1000,
msg: "OK",
data: {
// normal data goes here if exists
}
}
present 具体 Entity 时挺好用的,但涉及到内嵌结构的时候就不灵了
// ok
present :items, Book.all, with: Entities::Book
// does not work
resources :books do
get do
present :code, 1000
present :msg, "OK"
present :data do
present :items, Book.all, with: Entities::Book
end
end
end
本来手动组织这样的结构是微不足道的,引入框架后反而这个过程变得异常复杂和不灵活!~ 请问有什么替代方法吗?
貌似这段代码也不行。
# does not work
present :data, present(:items, Book.all, with: Entities::Book)
建议写进 entity 里。本来 json 的结构 grape 都是交给 grape-entity 负责的。换用 jbuilder 结果是同一回事。
直接定义一个 format 格式的函数 helper 也可以。这样也统一了返回格式。
def format(data, msg="ok", code=200)
{data: data, msg: msg, code: code}
end
楼主你用的什么 Entity,grape 的 Entity 非常灵活方便啊 内嵌复用什么的妥妥的
module Entities
class ProductService < Grape::Entity
expose :name
expose :description
expose :resource_category, using: ::Entities::ResourceCategory
end
end
我们现在这样做的,将 rescue_from formate 成约束的协议,然后定义正常的 formatter 和出错时的 formatter
rescue_from ActiveRecord::RecordNotFound do |e|
Rack::Response.new(
{
meta:{
status: :not_found,
msg: e.message
}
}.to_json, 404).finish
end
...
...
formatter :json, lambda {|object,env|
{ :meta => { status: :ok, msg: "" }, :data => object }.to_json
}
error_formatter :json, lambda { |message, backtrace, options, env|
{ :meta => { status: message[:status], msg: message[:msg] }}.to_json
}
碰到需要容错的地方,用 grape 提供的 error!
error!({ msg: 'Email has been registered', status: :registered }, 200)
#返回值
{
"meta": {
"status": "registered",
"msg": "Email has been registered"
}
}
然后正常的返回是这样
order = Order.first
present order, with: Entities::Order
# 返回值
{
"meta": {
"status": "ok",
"msg": ""
},
"data": {
"id": 278,
"text": "order1"
}
}
#ActiveRecord::RecordNotFound
{
"meta": {
"status": "not_found",
"msg": "Couldn't find City with 'id'=22"
}
}
Entity(模板)仅仅定义需要对外暴露的 data,而不需要去关心 meta
@hammer 1. grape-jbuilder 看起来有点糟糕。2. grape 与 web 分离,做成两个项目,ActiveRecord 怎么复用?
@yukihiro_matz rails 太重了,似乎不是为 web service 设计的,我也不想把 web 代码和接口代码交织在一起,接口可能需要 token 认证等等,web 代码可能不用。另外两者的错误处理也不同。
@hardywu 嗯,不行。查看代码发现 present 并不是直接返回一个 Hash, 而是做了一些副作用的事,把结果赋值给 @body。https://github.com/intridea/grape/blob/a0447887b46902c392973aac6e7623f6fd63fd5d/lib/grape/dsl/inside_route.rb#L169.
#14 楼 @rbprocareer 加 Grape 在 Gemfile 正是为了复用 ActiveRecord 要不用可以直接上 sinatra、pardino 这些了
#18 楼 @rbprocareer , AR 可以自己独立使用。不管是在 sinatra 还是在别的什么 framework 里。 这里是我自写的一个 rails-like web framework, 里面就直接用的 AR. https://github.com/suffering/learnmvc/blob/master/srbmvc/lib/srbmvc.rb#L34 做这样的简单设置后,就可以像是在 rails 里一样使用 AR 了。
哪些东西REPEAT YOURSLEF
了?或者说哪些东西在使用 AR 时导致代码一再重复了?
避免 grape 重复代码,可以参考 ruby-china 的源码:https://github.com/ruby-china/ruby-china/tree/master/app/grape
另外,rails 中 grape 的使用与 ORM 无关,资料查询与处理的方法都在 model 中写好,grape 中直接用就可以了。
@suffering 当将 web 代码和 api 代码分成两个项目,部署成两个服务后,AR 代码要么重写一遍,要么一个项目写好后,简单粗暴地 copy & paste 到另一个项目,要么做成一个 gem 啥的进行共享,使用 bundler 导入。。。视乎都不是好办法