Sinatra Nested Routes

sinatra ruby scanty rest routes

Sun Aug 30 20:44:23 -0700 2009

Okay, so the blog I am using for nvr.frgt.me is called scanty, which is written on top of sinatra, which is a classy DSL for ruby RESTful services. Buzzwords out of the way, let me show you a little bit of syntax which will work with patch I have been working on for my favorite tiny web DSL:

routes do |base_url|

    ### Specify your HTTP method with the block to be executed:
    GET { redirect '/posts/all' }

   
    ####  /posts actions  ####
    
    ### You can nest with ``/'' syntax - and no quotes. I hate quotes...
    base_url/posts do |posts|
        
        GET { redirect '/posts/all' }
        POST {
            require_auth
            @p = Post.new(params[:post]).save
            redirect "/posts/#{@p.slug}" 
        }
        
        ### The syntax starts to fight you when you accept only one action...
        posts/all do
            GET {
                @posts = Post.all
                haml :index
            }
        end

        #### ...so the following (sinatra-esque) shorthand is available.
        GET posts/create {
                require_auth
                @post = Post.new
                render :edit
         }
        
        ### You can nest within a block (obviously...) and use symbols to
        ### refer to wildcards in your URL which will be added to the
        ### ``params'' hash
        posts/:slug do |post|
            
            GET {
                @post = Post.find_by_slug(params[:slug])
                haml :post
            }
            PUT {
                require_auth
                Post.find_by_slug(params[:slug]).update(params[:post])
                haml :post
            }
            DELETE {
                require_auth
                Post.find_by_slug(params[:slug]).delete
                redirect '/posts/all'
            }
            GET post/edit {
                require_auth
                @post = Post.find_by_slug(params[:slug])
                render :edit
            }
        end
    end

    ####  admin actions ####

    ### Hey! You can double, triple, or even quadruple slash if you like.
    ### Any more than 4, and I think the dark lord returns...
    base_url/admin/login do
        GET  {
            if logged_in?
                redirect '/posts/all'
            else
                haml :login
            end
        }
        POST {
            if auth(params[:password])
                redirect '/posts/all'
            else
                haml :login
            end
        }
    end
end

So then, this is a work in progress, and clearly the syntax can use some massaging. At this point, I think that the perfect use case is in building multiple REST applications into the same app, like so (this is pseudocode):

routes do |base_url|

    GET base_url/sum { render params[:operand1].to_i + params[:operand2].to_i }

    base_url/photos do |photos|
 
        GET  { render Photos.all }
        POST { redirect "photos/#{Photos.new(params[:photo]).id}" }

        photos/:photo_id do
            GET    { render Photos.find(params[:photo_id]) }
            PUT    { render Photos.find(params[:photo_id]).replace(params[:photo]) }
            DELETE { Photos.find(params[:photo_id]).delete; redirect '/photos' }
        end

    end

end
blog comments powered by Disqus