3

我对 Ruby 并不陌生,但我在 Ruby 中使用 Grape API 编写了以下代码。@data = YAML.load()每次点击我都会打电话GET /api/v1/foo,有没有办法在葡萄中只加载一次并使用它?这种方式更加优化,不会YAML.load()每次都调用。我应该覆盖该initialize方法并super()为此操作添加一个吗?

谢谢,

require 'grape'
require 'json'
require "yaml"

module MyProject
  CONFIG_FILE = "./config.yml"

  class Api < Grape::API
    rescue_from :all
    prefix 'api'
    version 'v1'
    format :json

    resources :foo do
      get do
        @data = YAML.load(File.open(MyProject::CONFIG_FILE))
      end
    end
  end
end
4

2 回答 2

3

简短的回答是,这Grape与您的想法不太一样,并且属性变量MyProject::Api不是您的新 Web 服务的前进方向。然而,这是一个有趣的问题,值得探索为什么会这样。

如果您在块puts self.inspect内添加 a 并使用 运行,当您调用路由时,您应该会看到它实际上是一个对象。此外,无论您尝试对实例变量做什么,对于每个请求,它们总是以相同的状态开始。这是因为将您的路由定义转换为准备好的对象,将大量定义数据和设置放入一个可快速访问的表单中(这样就不会在每个请求中都计算出来)。最终,在每个请求中, 包括您的块(以及您为路由定义的其他详细信息)在内的匹配对象在被调用之前都会被复制,这意味着在请求之间不会维护该状态。resources :foorackupselfGrape::EndpointGrapeGrape::EndpointGrape::Endpoint

这可能看起来很复杂,但大多数涵盖 Web 服务请求的框架都会做类似的事情。通常,您不希望请求处理状态在请求之间持续存在。具有更大范围的框架——例如 Rails——有地方为你规划了更多的持久性数据。葡萄没有这个定义,这有其优点和缺点。一个明显的优点是您可以更自由地使用您希望使用的任何其他数据持久性方法。

23tux 的回答会立即为您整理好加载配置。虽然我不完全确定@@data端点块如何访问(它甚至可能在变量周围创建一个闭包)。

从长远来看,您应该考虑将配置管理移出您的MyProject::Api课程,并通过 Grape 的helpers方法将其作为一个模块包含在内(如果您有兴趣,我很乐意提供一个示例)。

编辑:基于您当前代码的示例,但将配置管理移动到单独的模块:

require 'grape'
require 'json'
require "yaml"

module MyProject

  module Config
    CONFIG_FILE = "./config.yml"
    @@data = nil
    def config
      @@data ||= YAML.load( File.open( CONFIG_FILE ) )
    end
  end

  class Api < Grape::API
    rescue_from :all
    prefix 'api'
    version 'v1'
    format :json

    helpers MyProject::Config

    resources :foo do
      get do
        config
      end
    end
  end
end

这在结构上比 23tux 的答案更进一步,但仍然没有完全区分存储(和缓存等)与 api 访问的关注点。随着您向更复杂的 Web 服务迈进,您将希望保持 Grape 路由定义简单,只使用少量管理或操作数据的逻辑 - 嗯,至少从块中直接看到。

Grape 定义与其他可能管理配置、日志记录、身份验证和其他服务的 gem 之间链接的一种方法是通过 Grape 的helpers方法。Grape 还为常见任务提供了一些内置的辅助方法。

用于将共享函数添加到 Grape的主要例外helpers MyModule是当您想要管理来自核心应用程序的显示数据对象(也称为“模型”)时。为此,您有几个选择,但grape-entitygem 和present方法并不是一个糟糕的起点。

于 2013-04-30T09:20:50.547 回答
1

如果@data整个 api 都一样,并且在任何时候都不会改变,只需使用一个类变量

require 'grape'
require 'json'
require "yaml"

module MyProject
  CONFIG_FILE = "./config.yml"

  class Api < Grape::API
    @@data = YAML.load(File.open(MyProject::CONFIG_FILE))

    rescue_from :all
    prefix 'api'
    version 'v1'
    format :json

    resources :foo do
      get do
        puts @@data
      end
    end
  end
end

未经测试,但通过这种方式,您可以确保数据仅在加载Api类时加载一次

于 2013-04-30T08:30:59.450 回答