Sinatra

Lightweight microframework. Specialized for API and microservice development, works with minimal configuration.

RubyFrameworkMicroframeworkDSLLightweightWeb DevelopmentAPI Development

GitHub Overview

sinatra/sinatra

Classy web-development dressed in a DSL (official / canonical repo)

Stars12,339
Watchers371
Forks2,071
Created:January 14, 2009
Language:Ruby
License:MIT License

Topics

rackrubysinatraweb-framework

Star History

sinatra/sinatra Star History
Data as of: 8/13/2025, 01:43 AM

Web Framework

Sinatra

Overview

Sinatra is a lightweight and flexible microframework for Ruby web development. With the catchphrase "little framework that shines," it provides a simple and intuitive DSL (Domain Specific Language) that enables rapid development of web applications and APIs with minimal code.

Details

Sinatra was originally developed by Blake Mizerachy in 2007 and is currently maintained by Tom Christie and many contributors as an open-source microframework. The latest version is 4.1.1, featuring Rack 3 support, lifecycle events (on_start/on_stop), and Puma as the default server.

Key architectural features:

  • Microframework Design: Minimal core functionality with high flexibility
  • DSL-Centered Development: Intuitive route definitions (get '/' do ... end)
  • Rack Compliance: Compatibility with rich Rack middleware ecosystem
  • Modular Design: Choice between classic and modular application styles
  • Extension Ecosystem: Rich extensions like sinatra-contrib and rack-protection

Sinatra adopts a philosophy opposite to "convention over configuration," allowing developers to choose only the necessary features. This makes it ideal for API development, prototyping, and microservices construction. It's adopted by companies like Netflix, LinkedIn, and GitHub (partially).

Pros and Cons

Pros

  • Extremely Simple: Create web applications with just a few lines of code
  • Low Learning Curve: Intuitive DSL that's easy for beginners to understand (Learning curve ★★★★★)
  • High Flexibility: Framework-agnostic design allows complete freedom
  • Lightweight & High Performance: Minimal overhead with fast execution
  • Rack Compatibility: Easy integration of rich Rack middleware
  • Rapid Development: Quick construction from prototyping to production
  • Modular Support: Well-organized design even for large applications
  • Test Support: Efficient test creation with Rack::Test integration

Cons

  • Limited Features: No built-in ORM, admin interface, or authentication
  • Development Scale Constraints: Less suitable for large full-stack development compared to Rails
  • Ecosystem: Limited third-party libraries compared to Rails
  • Configuration Burden: Complex configuration when combining extensions
  • Security: Security implementation responsibility falls on developers
  • Learning Resources: Fewer Japanese learning materials compared to Rails

Key Links

Code Examples

Hello World

# hello.rb
require 'sinatra'

get '/' do
  'Hello World!'
end

get '/hello/:name' do
  "Hello #{params['name']}!"
end

# Start server: ruby hello.rb
# Access via browser: http://localhost:4567

Routing and HTTP Methods

require 'sinatra'

# GET request
get '/users' do
  "Display user list"
end

# POST request
post '/users' do
  "Create user: #{params['name']}"
end

# PUT request
put '/users/:id' do
  "Update user ID #{params['id']}"
end

# DELETE request
delete '/users/:id' do
  "Delete user ID #{params['id']}"
end

# Regular expression routing
get /\/hello\/(\w+)/ do
  "Hello, #{params['captures'].first}!"
end

# Optional parameters
get '/posts/:format?' do
  format = params['format'] || 'html'
  "Format: #{format}"
end

Templates and Views

require 'sinatra'

# Using ERB templates
get '/' do
  erb :index
end

# Using Haml templates
get '/haml' do
  haml :index
end

# Inline template
get '/inline' do
  erb '<h1>Hello <%= @name %>!</h1>', locals: { name: 'Sinatra' }
end

# Custom layout
get '/custom' do
  erb :content, layout: :custom_layout
end

# views/index.erb
# <h1>Welcome to Sinatra!</h1>
# <p>Current time: <%= Time.now %></p>

# views/layout.erb
# <html>
#   <body>
#     <%= yield %>
#   </body>
# </html>

JSON and API Development

require 'sinatra'
require 'json'

# JSON response
get '/api/users' do
  content_type :json
  users = [
    { id: 1, name: 'John', email: '[email protected]' },
    { id: 2, name: 'Jane', email: '[email protected]' }
  ]
  users.to_json
end

# Receiving JSON data
post '/api/users' do
  request.body.rewind
  data = JSON.parse(request.body.read)
  
  # User creation logic
  new_user = {
    id: 3,
    name: data['name'],
    email: data['email']
  }
  
  content_type :json
  status 201
  new_user.to_json
end

# Error handling
get '/api/users/:id' do
  user_id = params['id'].to_i
  
  if user_id <= 0
    status 400
    { error: 'Invalid user ID' }.to_json
  else
    { id: user_id, name: "User#{user_id}" }.to_json
  end
end

Sessions and Middleware

require 'sinatra'

# Enable sessions
enable :sessions

get '/' do
  session[:visits] ||= 0
  session[:visits] += 1
  "Visit count: #{session[:visits]}"
end

# Using Rack middleware
use Rack::Auth::Basic, "Restricted Area" do |username, password|
  username == 'admin' && password == 'secret'
end

# Custom middleware
class TimingMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    start_time = Time.now
    status, headers, body = @app.call(env)
    end_time = Time.now
    headers['X-Response-Time'] = (end_time - start_time).to_s
    [status, headers, body]
  end
end

use TimingMiddleware

Helper Methods and Filters

require 'sinatra'

# Helper method definition
helpers do
  def protected!
    return if authorized?
    headers['WWW-Authenticate'] = 'Basic realm="Restricted Area"'
    halt 401, "Authentication required\n"
  end

  def authorized?
    @auth ||= Rack::Auth::Basic::Request.new(request.env)
    @auth.provided? && @auth.basic? && @auth.credentials && 
    @auth.credentials == ['admin', 'secret']
  end

  def format_date(date)
    date.strftime('%B %d, %Y')
  end
end

# Before filter
before do
  @current_time = Time.now
end

# Filter for specific routes only
before '/admin/*' do
  protected!
end

# After filter
after do
  logger.info "Request completed: #{@current_time}"
end

get '/protected' do
  protected!
  "Welcome to admin area!"
end

get '/time' do
  "Current time: #{format_date(@current_time)}"
end

Modular Style

require 'sinatra/base'

class MyApp < Sinatra::Base
  # Configuration
  set :sessions, true
  set :static, true
  set :public_folder, 'public'

  # Helpers
  helpers do
    def current_user
      session[:user]
    end
  end

  # Route definitions
  get '/' do
    erb :index
  end

  post '/login' do
    if params['username'] == 'admin' && params['password'] == 'secret'
      session[:user] = params['username']
      redirect '/'
    else
      erb :login, locals: { error: 'Login failed' }
    end
  end

  get '/logout' do
    session.clear
    redirect '/'
  end

  # Start application (development)
  run! if app_file == $0
end

# config.ru (Rackup file)
# require_relative 'myapp'
# run MyApp

Error Handling and Response Control

require 'sinatra'

# Error handling
not_found do
  erb :not_found
end

error do
  'An error occurred: ' + env['sinatra.error'].message
end

# Custom error
error 500 do
  'Internal server error occurred'
end

# Status code and header setting
get '/teapot' do
  status 418
  headers 'Content-Type' => 'text/plain'
  "I'm a teapot!"
end

# Redirect
get '/old-page' do
  redirect '/new-page'
end

# Cache control
get '/cached' do
  cache_control :public, :max_age => 3600
  "This page is cached for 1 hour"
end

# File sending
get '/download' do
  send_file 'files/sample.pdf', 
            filename: 'sample.pdf',
            type: 'application/pdf'
end