在Grape中仅加载一次属性

时间:2013-04-29 22:00:52

标签: ruby json yaml rack grape

我对Ruby不熟悉,但我在Ruby中使用Grape API进行了以下编码。我每次点击@data = YAML.load()时都会调出GET /api/v1/foo,Grape中有没有办法只加载一次并使用它?这种方式更加优化,并且不会每次都调用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

2 个答案:

答案 0 :(得分:3)

简短的回答是Grape不能完全按照您的想法运作,MyProject::Api的属性变量不是您的新网络服务的前进方式。然而,这是一个有趣的问题,值得探讨为何如此。

如果您在puts self.inspect块中添加resources :foo并使用rackup运行,则在调用该路线时,您应该会看到self实际上是Grape::Endpoint 1}}对象。此外,无论您尝试使用实例变量,它们始终会针对每个请求以相同的状态启动。这是因为Grape将您的路径定义转换为准备好的Grape::Endpoint对象,其中许多定义数据和设置被放入一个可快速访问的形式(因此在每个请求中都没有计算出来)。最终,在每个请求中,匹配的Grape::Endpoint对象(包括您的块(以及您为路由定义的其他详细信息)在被调用之前都是重复的,这意味着请求之间不会维护状态。 / p>

这可能看起来很复杂,但大多数涉及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的helpers方法,可以在Grape定义与可能管理配置,日志记录,身份验证和其他服务的其他gem之间建立链接的一种方法。 Grape还有一些用于常见任务的内置辅助方法。

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

答案 1 :(得分: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类时仅加载一次数据