我一直在使用Grape编写类似Evernote的API,并且一直使用Collection + JSON(MIME类型" application / vnd.collection + json")。我现在也想支持JSON API(mime类型" application / vnd.api + json")。
(我之所以这样做是因为编写Ember客户端会更容易,因为Ember Data支持内置的JSON API。编写客户端JavaScript来解决我的问题可能更有意义,但我在Ruby方面比JavaScript更强大。)
我的目标是让服务器支持任一格式,并根据Accept标头选择哪一种格式。这是一个合理的事情,或者拥有多个JSON类型没有意义吗?似乎Grape不支持这一点。如果我只是错误的想法,那么下面的代码可能与该答案无关。
以下是我的服务器代码的一些相关部分:
class NotesServer < Grape::API
content_type :json, ‘application/json’
content_type :json_api, 'application/vnd.api+json'
formatter :json_api, lambda { |object, env| object.to_json_api }
content_type :collection_json, 'application/vnd.collection+json'
formatter :collection_json, lambda { |object, env| object.to_collection_json }
resource :notes do
desc 'Get a note.'
params do
requires :id, type: Integer, desc: 'Note ID.'
end
route_param :id do
get do
NoteRepresenter.new Note.find(params[:id])
end
end
end
...其中NoteRepresenter定义了to_json_api和to_collection_json。
这个想法是在两种情况下使用相同的Representer,但是根据Accept标头调用适当的方法。
当我使用任何Accept标头对此运行curl时,响应具有Content-Type:application / json,并且在representer上调用“to_json”。如果我遗漏content_type :json, ‘application/json’
行,我每次都会收到406 Not Acceptable响应。
我发现在Grape库中,在lib / grape / middleware / formatter.rb中,&#34;格式&#34;对于任何这些MIME类型,请求被视为JSON,因为vnd.collection +或vnd.api +部分是从标头中解析出来的。所以我的问题是,这是葡萄不支持我想要做的事情,还是我想做一些毫无意义的事情?
答案 0 :(得分:0)
我找到了一个合理的方法来做到这一点,我觉得我很满意,但我认为这完全不符合Grape希望你做的事情。
我创建了一个名为JsonFormatter的自定义格式化程序,因此我的服务器代码如下所示:
class NotesServer < Grape::API
formatter :json, JsonFormatter
# …
end
格式化程序本身:
module JsonFormatter
def self.call(object, env)
case env['HTTP_ACCEPT']
when 'application/vnd.api+json'
object.to_json_api
when 'application/vnd.collection+json'
object.to_collection_json
else
object.to_json
end
end
end
所以现在要在presenter对象上调用to_json_api或to_collection_api(或to_json),具体取决于Accept标头。我还没有解决的一个问题是在所有情况下Content-Type都设置为application / json。