Router responds 404 by default for non-matched routes

This commit is contained in:
PJ Dietz 2018-06-28 09:46:59 -04:00
parent 36b03b6ca2
commit 0a0d3c3bc9
5 changed files with 48 additions and 48 deletions

View File

@ -6,6 +6,7 @@ use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use WellRESTed\Dispatching\Dispatcher; use WellRESTed\Dispatching\Dispatcher;
use WellRESTed\Dispatching\DispatcherInterface; use WellRESTed\Dispatching\DispatcherInterface;
use WellRESTed\Message\Response;
use WellRESTed\Routing\Route\RouteFactory; use WellRESTed\Routing\Route\RouteFactory;
use WellRESTed\Routing\Route\RouteFactoryInterface; use WellRESTed\Routing\Route\RouteFactoryInterface;
use WellRESTed\Routing\Route\RouteInterface; use WellRESTed\Routing\Route\RouteInterface;
@ -27,7 +28,9 @@ class Router implements RouterInterface
/** @var RouteInterface[] Hash array mapping path prefixes to routes */ /** @var RouteInterface[] Hash array mapping path prefixes to routes */
private $patternRoutes; private $patternRoutes;
/** @var mixed[] List array of middleware */ /** @var mixed[] List array of middleware */
protected $stack; private $stack;
/** @var bool Call the next middleware when no route matches */
private $continue = false;
/** /**
* Create a new Router. * Create a new Router.
@ -91,7 +94,10 @@ class Router implements RouterInterface
} }
} }
// If no route exists, delegate to the next middleware. if (!$this->continue) {
return $response->withStatus(404);
}
return $next($request, $response); return $next($request, $response);
} }
@ -173,6 +179,12 @@ class Router implements RouterInterface
return $this; return $this;
} }
public function continue()
{
$this->continue = true;
return $this;
}
/** /**
* Return an instance to dispatch middleware. * Return an instance to dispatch middleware.
* *

View File

@ -28,8 +28,6 @@ class Server
private $transmitter; private $transmitter;
/** @var mixed[] List array of middleware */ /** @var mixed[] List array of middleware */
private $stack; private $stack;
/** @var ResponseInterface */
private $unhandledResponse;
public function __construct() { public function __construct() {
$this->stack = []; $this->stack = [];
@ -75,8 +73,8 @@ class Server
$response = $this->getResponse(); $response = $this->getResponse();
$next = function () { $next = function ($rqst, $resp) {
return $this->getUnhandledResponse(); return $resp;
}; };
$dispatcher = $this->getDispatcher(); $dispatcher = $this->getDispatcher();
@ -149,15 +147,6 @@ class Server
return $this; return $this;
} }
/**
* @param ResponseInterface $response
* @return Server
*/
public function setUnhandledResponse(ResponseInterface $response): Server {
$this->unhandledResponse = $response;
return $this;
}
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
/* Defaults */ /* Defaults */
@ -200,12 +189,4 @@ class Server
} }
return $this->transmitter; return $this->transmitter;
} }
private function getUnhandledResponse()
{
if (!$this->unhandledResponse) {
$this->unhandledResponse = new Response(404);
}
return $this->unhandledResponse;
}
} }

View File

@ -128,7 +128,8 @@ class RoutingTest extends TestCase
->addMiddleware(new HeaderAdderMiddleware( ->addMiddleware(new HeaderAdderMiddleware(
'Content-type', 'application/cat')) 'Content-type', 'application/cat'))
->register('GET', '/molly', new StringHandler('Molly')) ->register('GET', '/molly', new StringHandler('Molly'))
->register('GET', '/oscar', new StringHandler('Oscar')); ->register('GET', '/oscar', new StringHandler('Oscar'))
->continue();
$this->server->add($catRouter); $this->server->add($catRouter);
$dogRouter = $this->server->createRouter() $dogRouter = $this->server->createRouter()
@ -154,7 +155,8 @@ class RoutingTest extends TestCase
->addMiddleware(new HeaderAdderMiddleware( ->addMiddleware(new HeaderAdderMiddleware(
'Content-type', 'application/cat')) 'Content-type', 'application/cat'))
->register('GET', '/molly', new StringHandler('Molly')) ->register('GET', '/molly', new StringHandler('Molly'))
->register('GET', '/oscar', new StringHandler('Oscar')); ->register('GET', '/oscar', new StringHandler('Oscar'))
->continue();
$this->server->add($catRouter); $this->server->add($catRouter);
$dogRouter = $this->server->createRouter() $dogRouter = $this->server->createRouter()

View File

@ -361,9 +361,27 @@ class RouterTest extends TestCase
)->shouldHaveBeenCalled(); )->shouldHaveBeenCalled();
} }
public function testPropagatesToNextMiddlewareWhenNoRouteMatches() // ------------------------------------------------------------------------
// No Match
public function testWhenNoRouteMatchesByDefaultResponds404()
{ {
$this->request = $this->request->withRequestTarget("/no/match"); $this->request = $this->request->withRequestTarget("/no/match");
$response = $this->router->__invoke($this->request, $this->response, $this->next);
$this->assertEquals(404, $response->getStatusCode());
}
public function testWhenNoRouteMatchesByDefaultDoesNotPropagatesToNextMiddleware()
{
$this->request = $this->request->withRequestTarget("/no/match");
$this->router->__invoke($this->request, $this->response, $this->next);
$this->assertFalse($this->next->called);
}
public function testWhenNoRouteMatchesAndContinueModePropagatesToNextMiddleware()
{
$this->request = $this->request->withRequestTarget("/no/match");
$this->router->continue();
$this->router->__invoke($this->request, $this->response, $this->next); $this->router->__invoke($this->request, $this->response, $this->next);
$this->assertTrue($this->next->called); $this->assertTrue($this->next->called);
} }

View File

@ -182,36 +182,23 @@ class ServerTest extends TestCase
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// End of Stack // End of Stack
public function testResponds404ByDefaultWhenReachingEndOfStack() public function testReturnsLastDoublePassResponseAtEndOfStack()
{ {
$this->server->respond(); $defaultResponse = new Response(404);
$has404StatusCode = function ($response) { $this->server->setResponse($defaultResponse);
return $response->getStatusCode() === 404;
};
$this->transmitter->transmit( $this->server->add(
Argument::any(), function ($rqst, $resp, $next) {
Argument::that($has404StatusCode) return $next($rqst, $resp);
)->shouldHaveBeenCalled();
} }
);
public function testRespondsWithUnhandledResponseWhenReachingEndOfStack()
{
$unhandledResponse = (new Response(404))
->withBody(new Stream("I can't find it!"));
$this->server->setUnhandledResponse($unhandledResponse);
$this->server->respond(); $this->server->respond();
$isExpectedResponse = function ($response) use ($unhandledResponse) {
return $response === $unhandledResponse;
};
$this->transmitter->transmit( $this->transmitter->transmit(
Argument::any(), Argument::any(),
Argument::that($isExpectedResponse) $defaultResponse
)->shouldHaveBeenCalled(); )->shouldHaveBeenCalled();
} }