Architecture for a Modular, Component-Based Sinatra Application

Architecture for a modular, component-based Sinatra Application

This is similar to include's proposal, but it doesn't require access to the rackup file.

Write your various Handlers like:

class FoodHandler < Sinatra::Base
get '/chunky/:food' do
"Chunky #{params[:food]}!"
end
end

Then in your main application file:

require './lib/handlers/food_handler.rb'

class Main < Sinatra::Base
enable :sessions
... bla bla bla
use FoodHandler
end

I've used this kind of structure to build some fairly complex Sinatra apps. It scales just as well as Rails.

EDIT

To have your config file define the routes, you could do something like this:

class PlacesHandler < Sinatra::Base
# Given your example, this would define 'places/paris' and 'places/losangeles'
CONFIG['components'].select { |c| c['compontent_type'] == 'Mapper' }.each do |c|
get c['route'] do
@latitude = c['component_settings']['latitude']
@longitude = c['component_settings']['longitude']
end
end
end

What is meant by Modular in Sinatra?

It means that you can create one or more Sinatra apps like the one you outlined in your question, as independent modules within the same super-app, for instance tied together using Rack#map:

# config.ru

require 'app1'
require 'app2'

run Rack::Builder.new {
map "/app1" do
run App1.new
end

map "/app2" do
run App2.new
end
}

Standardizing api responses in a modular Sinatra application

With some help from #sinatra on irc.freenode.org, I managed to get it down to what I want. I added the following to MyApp:

def route_eval
result = catch(:halt) { super }
throw :halt, {"result" => result}
end

I then changed the following line in ResponseMiddleware:

response = {'status' => 'success', 'data' => body}

to

response = {'status' => 'success', 'data' => body["result"]}

and all my test cases passed.

How mix in routes in Sinatra for a better structure

You don't do include with Sinatra. You use extensions together with register.

I.e. build your module in a separate file:

require 'sinatra/base'

module Sinatra
module OtherRoutes
def self.registered(app)
app.get "/route1" do
...
end
end
end
register OtherRoutes # for non modular apps, just include this file and it will register
end

And then register:

class Server < Sinatra::Base
register Sinatra::OtherRoutes
...
end

It's not really clear from the docs that this is the way to go for non-basic Sinatra apps. Hope it helps others.

How to define a method to be called from the configure block of a modular sinatra application?

It seems the configure block is executed as the file is read. You simply need to move the definition of your method before the configure block, and convert it to a class method:

class MyApp < Sinatra::Base

def self.read_config_file()
# interpret a config file
end

configure :production do
myConfigVar = self.read_config_file()
end

configure :development do
myConfigVar = self.read_config_file()
end

end

Documenting Sinatra routes for extensions (Yard::Sinatra doesn't work)

You might want to take a look into Cachafla's YARD::Sinatra version of the gem: gem install cachafla-yard-sinatra

more concise url route pattern in sinatra

I haven't used it before, but there's an extension from the sinatra-contrib project that will let you nest like that.

http://www.sinatrarb.com/contrib/namespace.html

Then you could do something like this:

namespace '/v1' do
get '/command_1' {}
get '/command_2' {}
# etc
end


Related Topics



Leave a reply



Submit