Sinatra

軽量なマイクロフレームワーク。APIやマイクロサービス開発に特化し、最小限の設定で動作する。

RubyフレームワークマイクロフレームワークDSL軽量Web開発API開発

GitHub概要

sinatra/sinatra

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

スター12,339
ウォッチ371
フォーク2,071
作成日:2009年1月14日
言語:Ruby
ライセンス:MIT License

トピックス

rackrubysinatraweb-framework

スター履歴

sinatra/sinatra Star History
データ取得日時: 2025/8/13 01:43

Webフレームワーク

Sinatra

概要

Sinatraは、Rubyで書かれた軽量で柔軟性の高いマイクロWebフレームワークです。「little framework that shines」をキャッチフレーズに、シンプルで直感的なDSL(ドメイン固有言語)を提供し、最小限のコードでWebアプリケーションやAPIを迅速に開発できます。

詳細

Sinatraは2007年にBlake Mizerachyによって開発され、現在はTom Christieら多くの貢献者により維持されているオープンソースのマイクロフレームワークです。最新バージョンは4.1.1で、Rack 3対応、ライフサイクルイベント(on_start/on_stop)、Pumaデフォルトサーバー化などの機能が追加されています。

主要なアーキテクチャの特徴:

  • マイクロフレームワーク設計: 最小限のコア機能で高い柔軟性を実現
  • DSL中心の開発: 直感的なルーティング定義(get '/' do ... end
  • Rack準拠: 豊富なRackミドルウェアとの互換性
  • モジュラー設計: クラシックスタイルとモジュラースタイルの選択可能
  • 拡張エコシステム: sinatra-contrib、rack-protectionなど豊富な拡張

Sinatraは「設定より規約」の反対の哲学を採用し、必要な機能のみを選択して使用できるため、API開発、プロトタイピング、マイクロサービス構築に最適です。Netflix、LinkedIn、GitHub(部分的)などでも採用されています。

メリット・デメリット

メリット

  • 極めてシンプル: 数行のコードでWebアプリケーションを作成可能
  • 学習コストの低さ: 直感的なDSLで初心者にも理解しやすい(学習曲線★★★★★)
  • 高い柔軟性: フレームワークに縛られない自由な設計が可能
  • 軽量・高パフォーマンス: オーバーヘッドが少なく高速動作
  • Rack互換性: 豊富なRackミドルウェアを簡単に組み込み可能
  • 迅速な開発: プロトタイピングから本格運用まで短期間で構築
  • モジュール化対応: 大規模アプリケーションでも整理された設計が可能
  • テスト支援: Rack::Testとの連携で効率的なテスト作成

デメリット

  • 機能の制限: ORM、Admin画面、認証機能が標準で非搭載
  • 開発規模の制約: 大規模なフルスタック開発ではRailsより不利
  • エコシステム: Railsに比べてサードパーティライブラリが限定的
  • 設定の負担: 拡張機能の組み合わせ時に設定が複雑になる場合がある
  • セキュリティ: セキュリティ機能の実装が開発者に委ねられる
  • 学習リソース: Railsに比べて日本語の学習資料が少ない

参考ページ

書き方の例

Hello World

# hello.rb
require 'sinatra'

get '/' do
  'Hello World!'
end

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

# サーバー起動: ruby hello.rb
# ブラウザでアクセス: http://localhost:4567

ルーティングとHTTPメソッド

require 'sinatra'

# GET リクエスト
get '/users' do
  "ユーザー一覧を表示"
end

# POST リクエスト
post '/users' do
  "ユーザーを作成: #{params['name']}"
end

# PUT リクエスト
put '/users/:id' do
  "ユーザーID #{params['id']} を更新"
end

# DELETE リクエスト
delete '/users/:id' do
  "ユーザーID #{params['id']} を削除"
end

# 正規表現でのルーティング
get /\/hello\/(\w+)/ do
  "Hello, #{params['captures'].first}!"
end

# オプションパラメータ
get '/posts/:format?' do
  format = params['format'] || 'html'
  "形式: #{format}"
end

テンプレートとビュー

require 'sinatra'

# ERBテンプレート使用
get '/' do
  erb :index
end

# Hamlテンプレート使用
get '/haml' do
  haml :index
end

# インラインテンプレート
get '/inline' do
  erb '<h1>Hello <%= @name %>!</h1>', locals: { name: 'Sinatra' }
end

# レイアウト指定
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とAPI開発

require 'sinatra'
require 'json'

# JSON レスポンス
get '/api/users' do
  content_type :json
  users = [
    { id: 1, name: '太郎', email: '[email protected]' },
    { id: 2, name: '花子', email: '[email protected]' }
  ]
  users.to_json
end

# JSONデータの受信
post '/api/users' do
  request.body.rewind
  data = JSON.parse(request.body.read)
  
  # ユーザー作成処理
  new_user = {
    id: 3,
    name: data['name'],
    email: data['email']
  }
  
  content_type :json
  status 201
  new_user.to_json
end

# エラーハンドリング
get '/api/users/:id' do
  user_id = params['id'].to_i
  
  if user_id <= 0
    status 400
    { error: '無効なユーザーID' }.to_json
  else
    { id: user_id, name: "ユーザー#{user_id}" }.to_json
  end
end

セッションとミドルウェア

require 'sinatra'

# セッション有効化
enable :sessions

get '/' do
  session[:visits] ||= 0
  session[:visits] += 1
  "訪問回数: #{session[:visits]}"
end

# Rackミドルウェアの使用
use Rack::Auth::Basic, "Restricted Area" do |username, password|
  username == 'admin' && password == 'secret'
end

# カスタムミドルウェア
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

ヘルパーメソッドとフィルター

require 'sinatra'

# ヘルパーメソッド定義
helpers do
  def protected!
    return if authorized?
    headers['WWW-Authenticate'] = 'Basic realm="Restricted Area"'
    halt 401, "認証が必要です\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('%Y年%m月%d日')
  end
end

# Before フィルター
before do
  @current_time = Time.now
end

# 特定のルートでのみ実行されるフィルター
before '/admin/*' do
  protected!
end

# After フィルター
after do
  logger.info "リクエスト処理完了: #{@current_time}"
end

get '/protected' do
  protected!
  "管理画面へようこそ!"
end

get '/time' do
  "現在時刻: #{format_date(@current_time)}"
end

モジュラースタイル

require 'sinatra/base'

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

  # ヘルパー
  helpers do
    def current_user
      session[:user]
    end
  end

  # ルート定義
  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: 'ログインに失敗しました' }
    end
  end

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

  # アプリケーション起動(開発時)
  run! if app_file == $0
end

# config.ru (Rackupファイル)
# require_relative 'myapp'
# run MyApp

エラーハンドリングとレスポンス制御

require 'sinatra'

# エラーハンドリング
not_found do
  erb :not_found
end

error do
  'エラーが発生しました: ' + env['sinatra.error'].message
end

# カスタムエラー
error 500 do
  'サーバーエラーが発生しました'
end

# ステータスコードとヘッダー設定
get '/teapot' do
  status 418
  headers 'Content-Type' => 'text/plain'
  "I'm a teapot!"
end

# リダイレクト
get '/old-page' do
  redirect '/new-page'
end

# キャッシュ制御
get '/cached' do
  cache_control :public, :max_age => 3600
  "このページは1時間キャッシュされます"
end

# ファイル送信
get '/download' do
  send_file 'files/sample.pdf', 
            filename: 'sample.pdf',
            type: 'application/pdf'
end