Sinatra
軽量なマイクロフレームワーク。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
スター履歴
データ取得日時: 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