0

我如何限制我的 API 在 Rails 和 Grape 上仅接受和响应 json 格式,我已经尝试format :json过我的 Grape 控制器并且(例如)我可以在 example.com/api/v1/ping.json 上访问它,但是我也可以通过example.com/api/v1/ping.xml、example.com/api/v1/ping.foobar访问它,扩展列表还在继续……

我想做的事情是在 example.com/api/v1/ping.not_json_extensions 上抛出错误

我正在使用:

  • 导轨 (4.1.1)
  • 葡萄 (0.7.0)

/config/routes.rb

mount API::Base => '/api'

/控制器/api/base.rb

module API
 class Base < Grape::API
  mount API::V1::Base
 end
end

/controllers/api/v1/base.rb

module API
 module V1
  class Base < Grape::API
   format :json
   mount API::V1::Ping
  end
 end

结尾

/controllers/api/v1/ping.rb

module API
 module V1
  class Ping < Grape::API
    include API::V1::Defaults
    desc 'Returns pong.'
    get :ping do
      { ping: params[:pong] || 'pong' }
    end
  end
 end

结尾

4

1 回答 1

2

查看Grape 的源代码,这似乎是预期的行为,但防止内存泄漏的更改有效地破坏了它。

您可以通过向 API 类(在 /controllers/api/base.rb 中)添加显式检查来“手动”实现正确的行为:

before do
  # Make sure the format specified by the request extension is one
  # we support
  parts = request.path.split('.')

  if parts.size > 1
    extension = parts.last

    if !extension.eql? 'json'
      throw :error, {
        status: 406,
        message: "The requested format '#{extension}' is not supported."
      }
    end
  end
end

这段代码几乎是从 Grape 的源代码(在lib/grape/middleware/formatter.rb中)逐字复制的,也是 Grape 本身检查请求中使用的扩展名的方式。

在该文件中,negotiate_content_type负责检查请求的格式是否为 API 支持的格式,并明确优先考虑请求的扩展名。format_from_extension但是,从 URI 解析扩展名的方法也会检查格式是否受支持,如果不支持则返回nil,就好像根本没有扩展名一样。因此negotiate_content_type,如果请求的扩展名指定了不受支持的格式,则永远不会触发错误,即使它显然是要这样做的。

您可以通过更改formatter.rb:109中的代码来“修复”此问题

# avoid symbol memory leak on an unknown format
return extension.to_sym if content_type_for(extension)

简单地

return extension.to_sym

不过,评论表明代码以这种方式编写是有原因的,因此请谨慎行事。

于 2014-06-21T16:18:11.293 回答