sinatra

Sinatra Framework Guide

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "sinatra" with this command: npx skills add ar4mirez/samuel/ar4mirez-samuel-sinatra

Sinatra Framework Guide

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)

  • Use factory_bot for test data setup

  • Coverage target: >80% for business logic

Project Structure

Simple Application (Prototypes Only)

myapp/ ├── app.rb # All routes and config ├── config.ru # Rack configuration ├── Gemfile ├── public/ # Static assets ├── views/ # ERB/Haml templates │ ├── layout.erb │ └── index.erb └── spec/ └── app_spec.rb

Modular Application (Production)

myapp/ ├── config.ru # Rack entry point ├── Gemfile ├── Rakefile # Database tasks ├── app/ │ ├── main.rb # Sinatra::Base application class │ ├── routes/ # Route modules (one per resource) │ │ ├── auth.rb │ │ ├── users.rb │ │ └── posts.rb │ ├── models/ # ActiveRecord/Sequel models │ │ ├── user.rb │ │ └── post.rb │ ├── services/ # Business logic (no Sinatra imports) │ │ └── user_service.rb │ └── helpers/ # Reusable helper modules │ ├── auth_helper.rb │ └── response_helper.rb ├── config/ │ ├── database.yml │ └── environment.rb # Boot: dotenv, bundler, DB setup ├── db/ │ └── migrations/ ├── public/ ├── views/ └── spec/ ├── spec_helper.rb ├── routes/ └── models/

Key conventions:

  • 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'

class App < 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
  end
end

end end

Request & Response

Reading Request Data

JSON body (use a helper for safety)

def json_params @json_params ||= begin body = request.body.read body.empty? ? {} : JSON.parse(body, symbolize_names: true) end rescue JSON::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 modules

module AuthHelper def current_user @current_user ||= User.find_by(id: session[:user_id]) if session[:user_id] end

def require_login! halt 401, json(error: 'Unauthorized') unless current_user end

def require_admin! require_login! halt 403, json(error: 'Forbidden') unless current_user.admin? end end

module ResponseHelper def paginate(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 } }

end end

Register in the app

class App < Sinatra::Base helpers AuthHelper helpers ResponseHelper end

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.erb end

Custom layout

get '/admin' do erb :dashboard, layout: :admin_layout end

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

class App < 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::RecordNotFound do status 404 json error: 'Resource not found' end

error ActiveRecord::RecordInvalid do |e| status 422 json errors: e.record.errors.full_messages end

error JSON::ParserError do status 400 json error: 'Invalid JSON' end end

Environment-Specific Error Display

configure :development do enable :show_exceptions enable :logging end

configure :production do disable :show_exceptions enable :raise_errors end

Filters

Use before and after filters for cross-cutting concerns.

class App < Sinatra::Base

Run before every request

before do content_type :json if 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 end end

Modular Application Pattern

Application Class (app/main.rb)

require 'sinatra/base' require 'sinatra/json' require 'sinatra/namespace'

class App < 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 :development do require 'sinatra/reloader' register Sinatra::Reloader enable :logging end

Dir[File.join(dir, 'helpers', '*.rb')].each { |f| require f } helpers AuthHelper, ResponseHelper

Dir[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)

module Routes module Users def self.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
    rescue ActiveRecord::RecordInvalid => e
      status 422
      json errors: e.record.errors.full_messages
    end
  end
end

end end

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

External References

  • Sinatra Documentation

  • Sinatra Recipes

  • Sinatra GitHub

  • Sinatra Contrib

  • Rack Documentation

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

actix-web

No summary provided by upstream source.

Repository SourceNeeds Review
General

frontend-design

No summary provided by upstream source.

Repository SourceNeeds Review
General

blazor

No summary provided by upstream source.

Repository SourceNeeds Review