Class: Stipa::App

Inherits:
Object
  • Object
show all
Defined in:
lib/stipa/app.rb

Overview

User-facing DSL for defining routes and middleware.

Usage:

app = Stipa::App.new

app.use Stipa::Middleware::RequestId
app.use Stipa::Middleware::Timing
app.use Stipa::Middleware::Cors, origins: ['https://example.com']

app.get '/'            { |_req, res| res.body = 'Hello' }
app.get '/health'      { |_req, res| res.json(status: 'ok') }
app.post '/echo'       { |req, res|  res.body = req.body }
app.get %r{/users/(?<id>\d+)} { |req, res| res.json(id: req.params[:id].to_i) }

app.start(port: 3710)

Handler signature:

Handlers always receive (req, res) — both the Request and the Response.
Mutate `res` directly: res.body = ..., res.status = ..., res.json(...).
Return value of the block is ignored; mutating `res` is the contract.

Route matching:

- String patterns: exact path match only.
- Regexp patterns: full match via Regexp#match. Named capture groups
  (e.g., (?<id>\d+)) are placed into req.params as symbol keys.
- Routes are checked in insertion order; first match wins.

Middleware:

- call `use` before `start`. Order matters: first `use`-d runs first.
- The chain is compiled once at start time; calling `use` afterwards
  has no effect (a warning is logged).

Constant Summary collapse

HTTP_VERBS =
%w[get post put patch delete head options].freeze

Instance Method Summary collapse

Constructor Details

#initialize(views: nil, public: nil) ⇒ App

views: path to the views directory (enables ERB rendering via res.render) public: path to the public directory (enables static file serving)

When provided, Static middleware is automatically prepended.


47
48
49
50
51
52
53
54
# File 'lib/stipa/app.rb', line 47

def initialize(views: nil, public: nil)
  @routes          = []
  @stack           = MiddlewareStack.new
  @started         = false
  @logger          = Logger.new
  @template_engine = views  ? Template.new(views_dir: views)  : nil
  @public_dir      = public ? File.expand_path(public)        : nil
end

Instance Method Details

#start(**opts) ⇒ Object

Build the middleware chain and start the TCP server. Blocks until shutdown.



75
76
77
78
79
80
81
82
83
84
85
# File 'lib/stipa/app.rb', line 75

def start(**opts)
  @started = true
  # Prepend Static middleware automatically when a public dir is configured.
  # It runs before all user-registered middleware so static assets are served
  # without going through the full middleware stack.
  if @public_dir
    @stack.prepend(Middleware::Static, root: @public_dir)
  end
  chain = @stack.build(method(:dispatch))
  Server.new(app: chain, **opts).start
end

#use(middleware, **opts) ⇒ Object

Add a middleware to the stack. Must be called before start.



65
66
67
68
69
70
71
72
# File 'lib/stipa/app.rb', line 65

def use(middleware, **opts)
  if @started
    @logger.warn("use() called after start — #{middleware} will be ignored")
    return self
  end
  @stack.use(middleware, **opts)
  self
end