Class: Rubino::API::Server
- Inherits:
-
Object
- Object
- Rubino::API::Server
- Defined in:
- lib/rubino/api/server.rb
Overview
Rack app entry point. Wires the middleware stack + router and runs it under Puma.
Reads RUBINO_API_KEY from the environment when no key is passed explicitly; start! refuses to boot without one so the bearer-auth middleware is never bypassed. The pure Rack app (no Puma) is exposed via .build_app for tests and embedding.
server = Rubino::API::Server.new(port: 4820)
server.start!
Constant Summary collapse
- DEFAULT_PORT =
4820- DEFAULT_HOST =
Loopback by default (#69): the server speaks to a shell tool, so a routable bind is opt-in (–host 0.0.0.0 / RUBINO_API_HOST).
"127.0.0.1"
Class Method Summary collapse
-
.bind_url(host:, port:, tls_cert: nil, tls_key: nil) ⇒ #call, String
Composes the Rack middleware stack around the router.
- .build_app(router:, api_key:, logger: Rubino.logger) ⇒ Object
Instance Method Summary collapse
-
#initialize(port: DEFAULT_PORT, host: DEFAULT_HOST, api_key: nil, router: nil, logger: nil, tls_cert: nil, tls_key: nil) ⇒ Server
constructor
A new instance of Server.
-
#start! ⇒ Object
Boots Puma and blocks.
-
#tls? ⇒ Boolean
Whether this server will serve over TLS.
Constructor Details
#initialize(port: DEFAULT_PORT, host: DEFAULT_HOST, api_key: nil, router: nil, logger: nil, tls_cert: nil, tls_key: nil) ⇒ Server
Returns a new instance of Server.
32 33 34 35 36 37 38 39 40 41 |
# File 'lib/rubino/api/server.rb', line 32 def initialize(port: DEFAULT_PORT, host: DEFAULT_HOST, api_key: nil, router: nil, logger: nil, tls_cert: nil, tls_key: nil) @port = port @host = host @api_key = api_key || ENV.fetch("RUBINO_API_KEY", nil) @router = router || Router.new @logger = logger || Rubino.logger @tls_cert = tls_cert @tls_key = tls_key end |
Class Method Details
.bind_url(host:, port:, tls_cert: nil, tls_key: nil) ⇒ #call, String
Composes the Rack middleware stack around the router. Order matters: Observability is outermost (sees every status, including 500s from ErrorHandler), then ErrorHandler, then RateLimit (so /v1/health and /v1/metrics also get a per-IP ceiling before Auth waves them through), then JsonParser, then Auth closest to the router so unauthorized requests never reach operations.
Builds the Puma bind URL. When a TLS cert+key are configured it returns an ssl:// bind so Puma terminates TLS with the self-signed cert; the web client pins that cert (see Rubino::API::TLS). Otherwise it returns a plain tcp:// bind (local dev / fake stay HTTP).
83 84 85 86 87 88 |
# File 'lib/rubino/api/server.rb', line 83 def self.bind_url(host:, port:, tls_cert: nil, tls_key: nil) return "tcp://#{host}:#{port}" if tls_cert.nil? || tls_key.nil? query = URI.encode_www_form(cert: tls_cert, key: tls_key) "ssl://#{host}:#{port}?#{query}" end |
.build_app(router:, api_key:, logger: Rubino.logger) ⇒ Object
90 91 92 93 94 95 96 97 98 99 |
# File 'lib/rubino/api/server.rb', line 90 def self.build_app(router:, api_key:, logger: Rubino.logger) Rack::Builder.new do use Middleware::Observability, logger: logger use Middleware::ErrorHandler, logger: logger use Middleware::RateLimit use Middleware::JsonParser use Middleware::Auth, api_key: api_key run router end.to_app end |
Instance Method Details
#start! ⇒ Object
Boots Puma and blocks. Fails fast if no API key is configured.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/rubino/api/server.rb', line 51 def start! if @api_key.nil? || @api_key.empty? raise ConfigurationError, "RUBINO_API_KEY must be set to start the API server" end app = self.class.build_app(router: @router, api_key: @api_key, logger: @logger) @logger.info(event: "api.server.starting", host: @host, port: @port, tls: tls?) bind_url = self.class.bind_url(host: @host, port: @port, tls_cert: @tls_cert, tls_key: @tls_key) config = Puma::Configuration.new do |c| c.bind(bind_url) c.app(app) c.quiet end Puma::Launcher.new(config).run end |
#tls? ⇒ Boolean
Returns whether this server will serve over TLS.
44 45 46 |
# File 'lib/rubino/api/server.rb', line 44 def tls? !@tls_cert.nil? && !@tls_key.nil? end |