From 36cc5adaea0027f6d4ae0d123cc5a901432db533 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Fri, 4 Sep 2026 21:04:19 +1200 Subject: [PATCH] Delegate unmatched application requests Assisted-By: devx/eb377015-8099-4dd4-ae2e-835d6d6a6387 --- context/getting-started.md | 7 ++---- guides/getting-started/readme.md | 7 ++---- lib/lively/application.rb | 8 +++++-- test/lively/application.rb | 38 ++++++++++++++------------------ 4 files changed, 26 insertions(+), 34 deletions(-) diff --git a/context/getting-started.md b/context/getting-started.md index fd004a3..95b6ec2 100644 --- a/context/getting-started.md +++ b/context/getting-started.md @@ -128,11 +128,6 @@ class Application < Lively::Application end end - # Unmatched routes are passed here: - def handle(request) - delegate.call(request) - end - private def render(body) @@ -144,6 +139,8 @@ end Routes match exact paths and may accept one or more HTTP methods. Query parameters are decoded using `protocol-url` and passed to the handler as its second argument. Routes without an explicit method accept every method. +Requests which do not match a route are passed to the application's delegate. An application using client-side history routing can instead override `#handle` to return its index page for unmatched paths. + ## Live Reloading To enable live reloading, add the `io-watch` gem to your `gems.rb` file: diff --git a/guides/getting-started/readme.md b/guides/getting-started/readme.md index fd004a3..95b6ec2 100644 --- a/guides/getting-started/readme.md +++ b/guides/getting-started/readme.md @@ -128,11 +128,6 @@ class Application < Lively::Application end end - # Unmatched routes are passed here: - def handle(request) - delegate.call(request) - end - private def render(body) @@ -144,6 +139,8 @@ end Routes match exact paths and may accept one or more HTTP methods. Query parameters are decoded using `protocol-url` and passed to the handler as its second argument. Routes without an explicit method accept every method. +Requests which do not match a route are passed to the application's delegate. An application using client-side history routing can instead override `#handle` to return its index page for unmatched paths. + ## Live Reloading To enable live reloading, add the `io-watch` gem to your `gems.rb` file: diff --git a/lib/lively/application.rb b/lib/lively/application.rb index 5898509..c1d707a 100644 --- a/lib/lively/application.rb +++ b/lib/lively/application.rb @@ -101,15 +101,19 @@ def index # Handle a standard HTTP request which did not match a configured route. # @parameter request [Protocol::HTTP::Request] The incoming HTTP request. - # @returns [Protocol::HTTP::Response] The HTTP response with the rendered page. + # @returns [Protocol::HTTP::Response] The delegate response. def handle(request) - return Protocol::HTTP::Response[200, [], [self.index.call]] + return delegate.call(request) end # Add the standard application routes to the given router. # Override this method and call `super` to add application-specific routes. # @parameter router [Router] The router to configure. def configure_routes(router) + router.get("/") do + Protocol::HTTP::Response[200, [], [self.index.call]] + end + router.route("/live") do |request| Async::WebSocket::Adapters::HTTP.open(request, &self.method(:live)) || Protocol::HTTP::Response[400] end diff --git a/test/lively/application.rb b/test/lively/application.rb index e352cfc..0c0d291 100644 --- a/test/lively/application.rb +++ b/test/lively/application.rb @@ -207,27 +207,12 @@ def mock_page.connection; @connection; end end with "#handle" do - it "returns a 200 response" do - response = application.handle(Protocol::HTTP::Request.new("http", "localhost", "GET", "/")) + it "delegates unmatched requests" do + response = application.handle(Protocol::HTTP::Request.new("http", "localhost", "GET", "/unknown")) expect(response).to be_a(Protocol::HTTP::Response) - expect(response.status).to be == 200 - end - - it "returns HTML content" do - response = application.handle(Protocol::HTTP::Request.new("http", "localhost", "GET", "/")) - - expect(response.body).to be_a(Protocol::HTTP::Body::Buffered) - html = response.body.read - expect(html).to be_a(String) - expect(html).to be(:include?, "") - end - - it "includes application title in response" do - response = application.handle(Protocol::HTTP::Request.new("http", "localhost", "GET", "/")) - html = response.body.read - - expect(html).to be(:include?, "Lively::Application") + expect(response.status).to be == 404 + expect(response.read).to be == "Not Found" end end @@ -236,6 +221,15 @@ def mock_page.connection; @connection; end expect(application.router).to be_equal(application.router) end + it "routes the application index explicitly" do + response = application.router.call(Protocol::HTTP::Request.new("http", "localhost", "GET", "/")) + html = response.read + + expect(response.status).to be == 200 + expect(html).to be(:include?, "") + expect(html).to be(:include?, "Lively::Application") + end + it "can be extended by subclasses" do application_class = Class.new(Lively::Application) do def configure_routes(router) @@ -320,11 +314,11 @@ def configure_routes(router) expect(response.read).to be(:include?, "Hello, I'm Lively!") end - it "handles different paths correctly" do + it "delegates unmatched paths" do response = client.get("/some/other/path") - expect(response.status).to be == 200 - expect(response.read).to be(:include?, "Hello, I'm Lively!") + expect(response.status).to be == 404 + expect(response.read).to be == "Not Found" end end end