【问题标题】:modular Sinatra App, setting error handling & configuration globally模块化 Sinatra 应用程序,全局设置错误处理和配置
【发布时间】:2014-07-28 14:13:19
【问题描述】:

我正在使用 Sinatra 构建一个小型 Rub​​y API,我希望将一些错误和配置设置为在全局级别上工作,这样我就不需要在每个开始时设置它们类。

我的结构是这样的:

content_api.rb

require 'sinatra/base'
require 'sinatra/namespace'
require 'sinatra/json'
require 'service_dependencies'
require 'api_helpers'
require 'json'

module ApiApp
  class ContentApi < Sinatra::Base

    helpers Sinatra::JSON
    helpers ApiApp::ApiHelpers
    include ApiApp::ServiceDependencies

    before do
      content_type :json
    end

    get '/' do
      content = content_service.get_all_content
      content.to_json
    end

    get '/audio' do
      package =content_service.get_type 'Audio'
      package.to_json
    end

    get '/video' do
      package =content_service.get_type 'Video'
      package.to_json
    end

    get '/document' do
      package =content_service.get_type 'Document'
      package.to_json
    end

  end
end

config.ru:

$LOAD_PATH.unshift *Dir[File.join(File.dirname(__FILE__), '/src/**')]
$LOAD_PATH.unshift *Dir[File.join(File.dirname(__FILE__), '/src/api/**')]

require 'content_api'
require 'package_api'
require 'utility_api'
require 'sinatra/base'


configure do
  set :show_exceptions => false
end

error { |err| Rack::Response.new([{'error' => err.message}.to_json], 500, {'Content-type' => 'application/json'}).finish }

Rack::Mount::RouteSet.new do |set|
    set.add_route ApiApp::ContentApi, {:path_info => %r{^/catalogue*}}, {}, :catalogue
    set.add_route ApiApp::PackageApi, {:path_info => %r{^/package*}}, {}, :package
    set.add_route ApiApp::UtilityApi, {:path_info => %r{^/health_check*}}, {}, :health_check
  end

当我运行它时,它会正常运行,但是当我强制一个 500 错误(关闭 MongoDb)时,我得到一个标准的 html 类型错误,指出:

<p id="explanation">You're seeing this error because you have
enabled the <code>show_exceptions</code> setting.</p>

如果我添加

configure do
      set :show_exceptions => false
    end

    error { |err| Rack::Response.new([{'error' => err.message}.to_json], 500, {'Content-type' => 'application/json'}).finish }

在 content_api.rb 文件中,我收到一个 JSON 错误,如我所愿。 但是,当我正在构建这个模块时,我不想在每个课程的顶部重复自己。

有没有一种简单的方法来完成这项工作?

【问题讨论】:

    标签: ruby sinatra rack


    【解决方案1】:

    最简单的方法是重新打开Sinatra::Base 并在其中添加代码:

    class Sinatra::Base
      set :show_exceptions => false
    
      error { |err|
        Rack::Response.new(
          [{'error' => err.message}.to_json],
          500,
          {'Content-type' => 'application/json'}
        ).finish
      }
    end
    

    这可能是不可取的,如果您的应用包含其他非 json 模块,则会导致问题。

    更好的解决方案可能是创建一个可以在模块中使用的Sinatra extension

    module JsonExceptions
    
      def self.registered(app)
        app.set :show_exceptions => false
    
        app.error { |err|
          Rack::Response.new(
            [{'error' => err.message}.to_json],
            500,
            {'Content-type' => 'application/json'}
          ).finish
        }
      end
    end
    

    然后你可以通过在你的模块中注册它来使用它:

    # require the file where it is defined first
    class ContentApi < Sinatra::Base
      register JsonExceptions
      # ... as before
    end
    

    【讨论】:

    • 谢谢,将其创建为扩展是一种享受,我认为这样做更简洁,因为它只是在每个类的顶部重复一行。再次感谢
    【解决方案2】:

    作为替代方案,继承:

    class JsonErrorController < Sinatra::Base
      configure do
        set :show_exceptions => false
      end
    
      error { |err| Rack::Response.new([{'error' => err.message}.to_json], 500, {'Content-type' => 'application/json'}).finish }
    
    end
    
    class ContentApi < JsonErrorController
      # rest of code follows…
    end
    

    来自 Sinatra 启动并运行 p73:

    不仅是设置,Sinatra 课程的每个方面都将是 由其子类继承。这包括已定义的路线、所有 错误处理程序、扩展、中间件等。

    【讨论】:

    • 感谢 iain,我自己并不太喜欢这个解决方案,我个人喜欢扩展的想法,因为我们将 sinatra 用于 apis,我已经用自定义错误打开了扩展类成一个 gem 供我们内部使用
    • @Vade 当然,我想我也可能会针对这样的单一需求进行扩展。您可以考虑将两者混合,创建几个要在 API 中使用的扩展,并创建一个 ApiController 类,您可以从该类继承来创建新的 API。
    猜你喜欢
    • 2014-09-27
    • 2014-09-25
    • 1970-01-01
    • 2013-07-01
    • 2012-03-25
    • 1970-01-01
    • 2011-10-14
    • 1970-01-01
    • 2013-03-06
    相关资源
    最近更新 更多