Skip to content

Commit 2aa4f17

Browse files
committed
Allow router to start without routes, require logger
Fixes #7.
1 parent 565eeb2 commit 2aa4f17

File tree

4 files changed

+45
-33
lines changed

4 files changed

+45
-33
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
"amphp/php-cs-fixer-config": "^2",
4141
"league/uri": "^6",
4242
"phpunit/phpunit": "^9",
43-
"psalm/phar": "^5.6"
43+
"psalm/phar": "^5.6",
44+
"colinodell/psr-testlogger": "^1.2"
4445
},
4546
"minimum-stability": "beta",
4647
"prefer-stable": true,

examples/hello-world.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
$errorHandler = new DefaultErrorHandler();
3434

35-
$router = new Router($server, $errorHandler);
35+
$router = new Router($server, $logger, $errorHandler);
3636
$router->addRoute('GET', '/', new ClosureRequestHandler(function () {
3737
return new Response(HttpStatus::OK, ['content-type' => 'text/plain'], 'Hello, world!');
3838
}));

src/Router.php

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Amp\Http\Server\RequestHandler\ClosureRequestHandler;
1010
use FastRoute\Dispatcher;
1111
use FastRoute\RouteCollector;
12+
use Psr\Log\LoggerInterface;
1213
use function Amp\Http\Server\Middleware\stackMiddleware;
1314
use function FastRoute\simpleDispatcher;
1415

@@ -41,6 +42,7 @@ final class Router implements RequestHandler
4142
*/
4243
public function __construct(
4344
HttpServer $httpServer,
45+
private readonly LoggerInterface $logger,
4446
private readonly ErrorHandler $errorHandler,
4547
int $cacheSize = self::DEFAULT_CACHE_SIZE,
4648
) {
@@ -60,10 +62,18 @@ public function __construct(
6062
*/
6163
public function handleRequest(Request $request): Response
6264
{
63-
if (!$this->routeDispatcher) {
65+
if (!$this->running) {
6466
throw new \Error('HTTP server has not been started so the router has not been built');
6567
}
6668

69+
if (!$this->routeDispatcher) {
70+
if ($this->fallback !== null) {
71+
return $this->fallback->handleRequest($request);
72+
}
73+
74+
return $this->notFound($request);
75+
}
76+
6777
$method = $request->getMethod();
6878
$path = \rawurldecode($request->getUri()->getPath());
6979

@@ -248,12 +258,13 @@ private function onStart(): void
248258
throw new \Error("Router already started");
249259
}
250260

251-
if (empty($this->routes)) {
252-
throw new \Error("Router start failure: no routes registered");
253-
}
254-
255261
$this->running = true;
256262

263+
if (!$this->routes) {
264+
$this->logger->notice("No routes registered");
265+
return;
266+
}
267+
257268
$this->routeDispatcher = simpleDispatcher(function (RouteCollector $rc): void {
258269
$redirectHandler = new ClosureRequestHandler(static function (Request $request): Response {
259270
$uri = $request->getUri();
@@ -295,7 +306,7 @@ private function onStart(): void
295306

296307
private function onStop(): void
297308
{
298-
unset($this->routeDispatcher);
309+
$this->routeDispatcher = null;
299310
$this->running = false;
300311
}
301312
}

test/RouterTest.php

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,32 @@
33
namespace Amp\Http\Server;
44

55
use Amp\ByteStream\Payload;
6-
use Amp\CompositeException;
76
use Amp\Http\HttpStatus;
87
use Amp\Http\Server\Driver\Client;
98
use Amp\Http\Server\RequestHandler\ClosureRequestHandler;
109
use Amp\Socket\InternetAddress;
10+
use ColinODell\PsrTestLogger\TestLogger;
1111
use League\Uri;
1212
use PHPUnit\Framework\TestCase;
13-
use Psr\Log\NullLogger;
1413

1514
class RouterTest extends TestCase
1615
{
1716
private SocketHttpServer $server;
1817
private ErrorHandler $errorHandler;
18+
private TestLogger $testLogger;
1919

2020
protected function setUp(): void
2121
{
2222
parent::setUp();
2323

24+
$this->testLogger = new TestLogger();
2425
$this->server = $this->createMockServer();
2526
$this->errorHandler = $this->createErrorHandler();
2627
}
2728

2829
protected function createMockServer(): SocketHttpServer
2930
{
30-
$server = SocketHttpServer::createForDirectAccess(new NullLogger);
31+
$server = SocketHttpServer::createForDirectAccess($this->testLogger);
3132
$server->expose(new InternetAddress('127.0.0.1', 0));
3233
return $server;
3334
}
@@ -41,32 +42,31 @@ public function testThrowsOnInvalidCacheSize(): void
4142
{
4243
$this->expectException(\Error::class);
4344

44-
new Router($this->createMockServer(), $this->createErrorHandler(), 0);
45+
new Router($this->server, $this->testLogger, $this->errorHandler, 0);
4546
}
4647

4748
public function testRouteThrowsOnEmptyMethodString(): void
4849
{
4950
$this->expectException(\Error::class);
5051
$this->expectExceptionMessage('Amp\Http\Server\Router::addRoute() requires a non-empty string HTTP method at Argument 1');
5152

52-
$router = new Router($this->createMockServer(), $this->createErrorHandler());
53+
$router = new Router($this->server, $this->testLogger, $this->errorHandler);
5354
$router->addRoute("", "/uri", new ClosureRequestHandler(function () {
5455
}));
5556
}
5657

57-
public function testUpdateFailsIfStartedWithoutAnyRoutes(): void
58+
public function testLogsMessageWithoutAnyRoutes(): void
5859
{
59-
$router = new Router($this->server, $this->errorHandler);
60-
61-
$this->expectException(CompositeException::class);
62-
$this->expectExceptionMessage("Router start failure: no routes registered");
60+
$router = new Router($this->server, $this->testLogger, $this->errorHandler);
6361

6462
$this->server->start($router, $this->errorHandler);
63+
64+
self::assertTrue($this->testLogger->hasNotice('No routes registered'));
6565
}
6666

6767
public function testUseCanonicalRedirector(): void
6868
{
69-
$router = new Router($this->server, $this->errorHandler);
69+
$router = new Router($this->server, $this->testLogger, $this->errorHandler);
7070
$router->addRoute("GET", "/{name}/{age}/?", new ClosureRequestHandler(function (Request $req) use (&$routeArgs) {
7171
$routeArgs = $req->getAttribute(Router::class);
7272
return new Response;
@@ -93,7 +93,7 @@ public function testUseCanonicalRedirector(): void
9393

9494
public function testMultiplePrefixes(): void
9595
{
96-
$router = new Router($this->server, $this->errorHandler);
96+
$router = new Router($this->server, $this->testLogger, $this->errorHandler);
9797
$router->addRoute("GET", "{name}", new ClosureRequestHandler(function (Request $req) use (&$routeArgs) {
9898
$routeArgs = $req->getAttribute(Router::class);
9999
return new Response;
@@ -112,7 +112,7 @@ public function testMultiplePrefixes(): void
112112

113113
public function testStack(): void
114114
{
115-
$router = new Router($this->server, $this->errorHandler);
115+
$router = new Router($this->server, $this->testLogger, $this->errorHandler);
116116
$router->addRoute("GET", "/", new ClosureRequestHandler(function (Request $req) {
117117
return new Response(HttpStatus::OK, [], $req->getAttribute("stack"));
118118
}));
@@ -143,7 +143,7 @@ public function handleRequest(Request $request, RequestHandler $requestHandler):
143143

144144
public function testStackMultipleCalls(): void
145145
{
146-
$router = new Router($this->server, $this->errorHandler);
146+
$router = new Router($this->server, $this->testLogger, $this->errorHandler);
147147
$router->addRoute("GET", "/", new ClosureRequestHandler(function (Request $req) {
148148
return new Response(HttpStatus::OK, [], $req->getAttribute("stack"));
149149
}));
@@ -180,11 +180,11 @@ public function testMerge(): void
180180
return new Response(HttpStatus::OK, [], $req->getUri()->getPath());
181181
});
182182

183-
$routerA = new Router($this->server, $this->createErrorHandler());
183+
$routerA = new Router($this->server, $this->testLogger, $this->createErrorHandler());
184184
$routerA->prefix("a");
185185
$routerA->addRoute("GET", "{name}", $requestHandler);
186186

187-
$routerB = new Router($this->server, $this->createErrorHandler());
187+
$routerB = new Router($this->server, $this->testLogger, $this->createErrorHandler());
188188
$routerB->prefix("b");
189189
$routerB->addRoute("GET", "{name}", $requestHandler);
190190

@@ -211,7 +211,7 @@ public function testPathIsMatchedDecoded(): void
211211
return new Response(HttpStatus::OK);
212212
});
213213

214-
$router = new Router($this->server, $this->errorHandler);
214+
$router = new Router($this->server, $this->testLogger, $this->errorHandler);
215215
$router->addRoute("GET", "/fo+ö", $requestHandler);
216216

217217
$this->server->start($router, $this->errorHandler);
@@ -233,7 +233,7 @@ public function testFallbackInvokedOnNotFoundRoute(): void
233233
return new Response(HttpStatus::NO_CONTENT);
234234
});
235235

236-
$router = new Router($this->server, $this->errorHandler);
236+
$router = new Router($this->server, $this->testLogger, $this->errorHandler);
237237
$router->addRoute("GET", "/foo/{name}", $requestHandler);
238238
$router->setFallback($fallback);
239239

@@ -250,7 +250,7 @@ public function testNonAllowedMethod(): void
250250
return new Response(HttpStatus::OK);
251251
});
252252

253-
$router = new Router($this->server, $this->errorHandler);
253+
$router = new Router($this->server, $this->testLogger, $this->errorHandler);
254254
$router->addRoute("GET", "/foo/{name}", $requestHandler);
255255
$router->addRoute("DELETE", "/foo/{name}", $requestHandler);
256256

@@ -270,14 +270,14 @@ public function testMergeAfterStart(): void
270270

271271
$mockServer = $this->createMockServer();
272272

273-
$router = new Router($this->server, $this->errorHandler);
273+
$router = new Router($this->server, $this->testLogger, $this->errorHandler);
274274
$router->addRoute("GET", "/foo/{name}", $requestHandler);
275275

276276
$this->server->start($router, $this->errorHandler);
277277

278278
$this->expectException(\Error::class);
279279
$this->expectExceptionMessage('Cannot merge routers after');
280-
$router->merge(new Router($mockServer, $this->createErrorHandler()));
280+
$router->merge(new Router($mockServer, $this->testLogger, $this->createErrorHandler()));
281281
}
282282

283283
public function testPrefixAfterStart(): void
@@ -286,7 +286,7 @@ public function testPrefixAfterStart(): void
286286
return new Response(HttpStatus::OK);
287287
});
288288

289-
$router = new Router($this->server, $this->errorHandler);
289+
$router = new Router($this->server, $this->testLogger, $this->errorHandler);
290290
$router->addRoute("GET", "/foo/{name}", $requestHandler);
291291

292292
$this->server->start($router, $this->errorHandler);
@@ -302,7 +302,7 @@ public function testAddRouteAfterStart(): void
302302
return new Response(HttpStatus::OK);
303303
});
304304

305-
$router = new Router($this->server, $this->errorHandler);
305+
$router = new Router($this->server, $this->testLogger, $this->errorHandler);
306306
$router->addRoute("GET", "/foo/{name}", $requestHandler);
307307

308308
$this->server->start($router, $this->errorHandler);
@@ -318,7 +318,7 @@ public function testStackAfterStart(): void
318318
return new Response(HttpStatus::OK);
319319
});
320320

321-
$router = new Router($this->server, $this->errorHandler);
321+
$router = new Router($this->server, $this->testLogger, $this->errorHandler);
322322
$router->addRoute("GET", "/foo/{name}", $requestHandler);
323323

324324
$this->server->start($router, $this->errorHandler);
@@ -334,7 +334,7 @@ public function testSetFallbackAfterStart(): void
334334
return new Response(HttpStatus::OK);
335335
});
336336

337-
$router = new Router($this->server, $this->errorHandler);
337+
$router = new Router($this->server, $this->testLogger, $this->errorHandler);
338338
$router->addRoute("GET", "/foo/{name}", $requestHandler);
339339

340340
$this->server->start($router, $this->errorHandler);

0 commit comments

Comments
 (0)