Reputation: 2029
I am using Sinatra to build a small Ruby API, and I would like to get some of the errors and configurations set to work at a global level so that i don't need to set them at the start of each of the classes.
My structure is this:
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
When I run this, it will run okay, but when I force a 500 error (shut down MongoDb) I get a standard html type error that states:
<p id="explanation">You're seeing this error because you have
enabled the <code>show_exceptions</code> setting.</p>
If I add the
configure do
set :show_exceptions => false
end
error { |err| Rack::Response.new([{'error' => err.message}.to_json], 500, {'Content-type' => 'application/json'}).finish }
inside the content_api.rb file, then I get a JSON error returned as I would like to receive. however, as I am building this modular, I don't want to be repeating myself at the top of each class.
Is there a simple way to make this work?
Upvotes: 3
Views: 2081
Reputation: 12251
As an alternative, inheritance:
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
From Sinatra Up and Running p73:
Not only settings, but every aspect of a Sinatra class will be inherited by its subclasses. This includes defined routes, all the error handlers, extensions, middleware, and so on.
Upvotes: 2
Reputation: 79733
The simplest way to do this would be to reopen Sinatra::Base
and add the code there:
class Sinatra::Base
set :show_exceptions => false
error { |err|
Rack::Response.new(
[{'error' => err.message}.to_json],
500,
{'Content-type' => 'application/json'}
).finish
}
end
This is probably not advisable though, and will cause problems if your app includes other non-json modules.
A better solution might be to create a Sinatra extension that you could use in your modules.
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
You would then use it by registering it in your modules:
# require the file where it is defined first
class ContentApi < Sinatra::Base
register JsonExceptions
# ... as before
end
Upvotes: 3