Sinatra framework guardrails, patterns, and best practices for AI-assisted development.
Use when working with Sinatra projects, or when the user mentions Sinatra.
Provides lightweight Ruby web patterns, routing DSL, middleware, and REST API guidelines.
Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
Sinatra framework guardrails, patterns, and best practices for AI-assisted development.
Use when working with Sinatra projects, or when the user mentions Sinatra.
Provides lightweight Ruby web patterns, routing DSL, middleware, and REST API guidelines.
Applies to: Sinatra 3.x, Ruby 3.0+, REST APIs, Microservices, Prototypes
Language Guide: @.claude/skills/ruby-guide/SKILL.md
Overview
Sinatra is a lightweight DSL for building web applications and APIs in Ruby. It maps HTTP verbs directly to Ruby blocks, providing minimal ceremony and maximum flexibility.
Use Sinatra when:
Building microservices or small-to-medium APIs
Rapid prototyping or proof-of-concept work
Lightweight webhooks, proxies, or internal tools
You want minimal framework overhead
Consider alternatives when:
You need a full MVC framework (use Rails)
You need built-in admin, ORM, and auth out of the box (use Rails)
Application complexity exceeds 10+ route modules (use Rails or Hanami)
Guardrails
Sinatra-Specific Guidelines
Use modular style (Sinatra::Base) for production applications
Classic style is acceptable for scripts and prototypes only
Use sinatra-contrib for JSON, namespaces, and reloader support
Use Puma as the production application server
Use Bundler for dependency management with a Gemfile
Separate routes into modules via register and Sinatra::Namespace
Extract helpers into dedicated modules under app/helpers/
Use service objects for business logic (keep routes thin)
Security Guidelines
Never hardcode secrets; use environment variables via dotenv
Set session_secret from ENV (not random fallback in production)
Validate all user input before processing
Use parameterized queries via ActiveRecord or Sequel ORM
Implement authentication checks with before filters
Use HTTPS in production with proper HSTS headers
Implement rate limiting via Rack middleware
Configure CORS restrictively (never * in production)
Testing Guidelines
Use RSpec with rack-test for HTTP integration tests
Use database_cleaner to reset state between tests
Test both success and error paths for every endpoint
Mock external services (never call real APIs in tests)
app/main.rb contains the Sinatra::Base subclass and wires everything together
app/routes/ holds one module per resource, registered via register
app/services/ holds business logic with no framework coupling
app/helpers/ holds modules included via helpers DSL
config/environment.rb boots dotenv, bundler, and database connection
Routing DSL
Sinatra maps HTTP verbs directly to Ruby blocks. Parameters are captured via :name symbols.
# Basic CRUD routes
get '/users' { json users:User.all.map(&:to_h) }
get '/users/:id' { json user: find_user!.to_h }
post '/users' { create_user }
put '/users/:id' { update_user }
delete '/users/:id' { delete_user }
Route Parameters
# Named parameters (available in params hash)
get '/users/:id'do
user = User.find(params[:id])
json user: user.to_h
end# Splat (wildcard) parameters
get '/files/*.*'do# params['splat'] => ['path/to/file', 'ext']end# Query parameters
get '/search'do# params[:q], params[:page]end# Regular expression routes
get %r{/posts/(\d+)} do |id|
Post.find(id)
end
Namespaced Routes
Use sinatra/namespace to group routes with shared prefixes.
require'sinatra/namespace'classApp < Sinatra::Base
register Sinatra::Namespace
namespace '/api/v1'do
namespace '/users'do
get { json users:User.all.map(&:to_h) }
post { create_user }
get '/:id'do
json user:User.find(params[:id]).to_h
endendendend
Request & Response
Reading Request Data
# JSON body (use a helper for safety)defjson_params@json_params ||= begin
body = request.body.read
body.empty? ? {} : JSON.parse(body, symbolize_names:true)
endrescueJSON::ParserError
halt 400, json(error:'Invalid JSON')
end# Form data
params[:field_name]
# Headers
request.env['HTTP_AUTHORIZATION']
request.content_type
request.accept?('application/json')
Response Patterns
# JSON response (via sinatra/json)
get '/health'do
json status:'ok', timestamp:Time.now.iso8601
end# Status codes
post '/users'do
user = User.create!(json_params)
status 201
json user: user.to_h
end# Halt with error (stops execution immediately)
halt 404, json(error:'Not found')
halt 401, json(error:'Unauthorized')
halt 422, json(errors: user.errors.full_messages)
# Redirect
redirect '/login'
redirect '/users', 303# See Other# Headers
headers 'X-Custom-Header' => 'value'
content_type :json
Helpers
Define reusable methods available in routes and views.
# In modular style, define helper modulesmoduleAuthHelperdefcurrent_user@current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
enddefrequire_login!
halt 401, json(error:'Unauthorized') unless current_user
enddefrequire_admin!
require_login!
halt 403, json(error:'Forbidden') unless current_user.admin?
endendmoduleResponseHelperdefpaginate(collection, per_page:20)
page = (params[:page] || 1).to_i
per = (params[:per_page] || per_page).to_i
total = collection.count
items = collection.offset((page - 1) * per).limit(per)
{ items: items, meta: { page: page, per_page: per, total: total } }
endend# Register in the appclassApp < Sinatra::Base
helpers AuthHelper
helpers ResponseHelperend
Views & Templates
Sinatra supports ERB, Haml, Slim, and other Tilt-compatible template engines. For JSON APIs, skip views entirely and use the json helper.
# Render a template (looks in views/ directory)
get '/'do@title = 'Home'
erb :index# renders views/index.erbend# Custom layout
get '/admin'do
erb :dashboard, layout::admin_layoutend
Use template inheritance via <%= yield %> in views/layout.erb. Keep logic out of templates; use helpers and instance variables set in routes.
Error Handling
Error Handlers
classApp < Sinatra::Base# Named error handlers
not_found do
json error:'Not found'end
error do
json error:'Internal server error'end# Catch specific exceptions
error ActiveRecord::RecordNotFounddo
status 404
json error:'Resource not found'end
error ActiveRecord::RecordInvaliddo |e|
status 422
json errors: e.record.errors.full_messages
end
error JSON::ParserErrordo
status 400
json error:'Invalid JSON'endend
Use before and after filters for cross-cutting concerns.
classApp < Sinatra::Base# Run before every request
before do
content_type :jsonif request.accept?('application/json')
end# Scoped to path prefix
before '/api/*'do
content_type :json
authenticate_token!
end# Run after every request
after do
response.headers['X-Request-Id'] = SecureRandom.uuid
endend
Modular Application Pattern
Application Class (app/main.rb)
require'sinatra/base'require'sinatra/json'require'sinatra/namespace'classApp < Sinatra::Base
register Sinatra::Namespace
configure do
set :server, :puma
set :root, File.dirname(__FILE__)
set :views, proc { File.join(root, '..', 'views') }
enable :sessions
set :session_secret, ENV.fetch('SESSION_SECRET')
end
configure :developmentdorequire'sinatra/reloader'
register Sinatra::Reloader
enable :loggingendDir[File.join(__dir__, 'helpers', '*.rb')].each { |f| require f }
helpers AuthHelper, ResponseHelperDir[File.join(__dir__, 'routes', '*.rb')].each { |f| require f }
register Routes::Users
register Routes::Auth
get('/health') { json status:'ok' }
not_found { json error:'Not found' }
error { json error:'Internal server error' }
end
Route Module (app/routes/users.rb)
moduleRoutesmoduleUsersdefself.registered(app)
app.namespace '/api/v1/users'do
get { json users:User.all.map(&:to_h) }
get('/:id') { json user:User.find(params[:id]).to_h }
post do
user = User.create!(json_params)
status 201
json user: user.to_h
rescueActiveRecord::RecordInvalid => e
status 422
json errors: e.record.errors.full_messages
endendendendend
Rack Configuration (config.ru)
require'bundler/setup'Bundler.require(:default, ENV.fetch('RACK_ENV', 'development'))
require_relative 'config/environment'
require_relative 'app/main'
run App
Commands Reference
# Install dependencies
bundle install
# Run development server (with auto-reload)
bundle exec ruby app.rb
# Or with rackup
bundle exec rackup -p 4567
# Run tests
bundle exec rspec
bundle exec rspec --format documentation
# Run with coverage
bundle exec rspec --format progress --require simplecov
# Database tasks
bundle exec rake db:create
bundle exec rake db:migrate
bundle exec rake db:rollback
# Production server
bundle exec puma -C config/puma.rb
# Console (interactive)
bundle exec pry -r ./config/environment
# Docker
docker build -t myapp .
docker run -p 4567:4567 myapp
Dependencies
Gem
Purpose
sinatra
Web framework DSL
sinatra-contrib
Extensions: JSON, namespace, reloader
puma
Production application server
rake
Task runner for migrations
dotenv
Environment variable loading
activerecord / sequel
ORM for database access
pg
PostgreSQL adapter
bcrypt
Password hashing (has_secure_password)
jwt
JSON Web Token authentication
rspec
Test framework
rack-test
HTTP request helpers for Rack apps
database_cleaner-active_record
DB cleanup between tests
factory_bot
Test data factories
Advanced Topics
For detailed code examples and advanced patterns, see:
references/patterns.md -- Database integration, authentication (sessions and JWT), Rack middleware, testing patterns, deployment, and Sequel ORM alternative