We can write
get '/foo' do
...
end
and
post '/foo' do
...
end
which is fine. But can I combine multiple HTTP verbs in one route?
We can write
get '/foo' do
...
end
and
post '/foo' do
...
end
which is fine. But can I combine multiple HTTP verbs in one route?
This is possible via the multi-route
extension that is part of sinatra-contrib:
require 'sinatra'
require "sinatra/multi_route"
route :get, :post, '/foo' do
# "GET" or "POST"
p request.env["REQUEST_METHOD"]
end
# Or for module-style applications
class MyApp < Sinatra::Base
register Sinatra::MultiRoute
route :get, :post, '/foo' do
# ...
end
end
However, note that you can do this simply yourself without the extension via:
foo = lambda do
# Your route here
end
get '/foo', &foo
post '/foo', &foo
Or more elegantly as a meta-method:
def self.get_or_post(url,&block)
get(url,&block)
post(url,&block)
end
get_or_post '/foo' do
# ...
end
You might also be interested in this discussion on the feature.
FWIW, I just do it manually, with no helper methods or extensions:
%i(get post).each do |method|
send method, '/foo' do
...
end
end
Although if you're doing it a lot it of course makes sense to abstract that out.
Phrogz has a great answer, but if either lambdas or including sinatra-contrib isn't for you, then this meta method will achieve the same result as sinatra-contrib for your purposes:
# Provides a way to handle multiple HTTP verbs with a single block
#
# @example
# route :get, :post, '/something' do
# # Handle your route here
# end
def self.route(*methods, path, &block)
methods.each do |method|
method.to_sym
self.send method, path, &block
end
end
If you're a little wary of being able to send arbitrary methods to self
, then you can protect yourself by setting up a whitelist of allowed methods in an array, and then checking for the symbol's presence in the array.
# Provides a way to handle multiple HTTP verbs with a single block
#
# @example
# route :get, :post, '/something' do
# # Handle your route here
# end
def self.route(*methods, path, &block)
allowed_methods = [:get, :post, :delete, :patch, :put, :head, :options]
methods.each do |method|
method.to_sym
self.send(method, path, &block) if allowed_methods.include? method
end
end
Here's a service-unavailable server that I managed to get on single line :)
require 'sinatra';set port: ARGV[0]||80;%w.get post put patch options delete..map{|v|send(v,'*'){503}}
I actually used this to test the behavior of some client code in the face of 503s.