Skip to content
This repository has been archived by the owner on Jun 1, 2023. It is now read-only.

Commit

Permalink
add MethodNotAllowedException::getAllowedMethods()
Browse files Browse the repository at this point in the history
  • Loading branch information
azjezz committed Aug 29, 2019
1 parent b4ae8a9 commit 6a2ed8a
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 13 deletions.
12 changes: 12 additions & 0 deletions src/http-exceptions/MethodNotAllowedException.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,16 @@
namespace Facebook\HackRouter;

class MethodNotAllowedException extends HttpException {
public function __construct(
protected keyset<HttpMethod> $allowed,
string $message = '',
int $code = 0,
?\Exception $previous = null,
) {
parent::__construct($message, $code, $previous);
}

public function getAllowedMethods(): keyset<HttpMethod> {
return $this->allowed;
}
}
12 changes: 9 additions & 3 deletions src/router/BaseRouter.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace Facebook\HackRouter;

use namespace HH\Lib\Dict;
use namespace HH\Lib\{C, Dict};
use function Facebook\AutoloadMap\Generated\is_dev;

abstract class BaseRouter<+TResponder> {
Expand All @@ -27,6 +27,7 @@ final public function routeMethodAndPath(
$data = Dict\map($data, $value ==> \urldecode($value));
return tuple($responder, new ImmMap($data));
} catch (NotFoundException $e) {
$allowed = vec[];
foreach (HttpMethod::getValues() as $next) {
if ($next === $method) {
continue;
Expand All @@ -37,11 +38,16 @@ final public function routeMethodAndPath(
$data = Dict\map($data, $value ==> \urldecode($value));
return tuple($responder, new ImmMap($data));
}
throw new MethodNotAllowedException();

$allowed[] = $next;
} catch (NotFoundException $_) {
continue;
}
}
if (!C\empty($allowed)) {
throw new MethodNotAllowedException($allowed);
}

throw $e;
}
}
Expand All @@ -51,7 +57,7 @@ final public function routeRequest(
): (TResponder, ImmMap<string, string>) {
$method = HttpMethod::coerce($request->getMethod());
if ($method === null) {
throw new MethodNotAllowedException();
throw new MethodNotAllowedException(vec(HttpMethod::getValues()));
}
return $this->routeMethodAndPath($method, $request->getUri()->getPath());
}
Expand Down
38 changes: 28 additions & 10 deletions tests/RouterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
namespace Facebook\HackRouter;

use function Facebook\FBExpect\expect;
use namespace HH\Lib\Dict;
use namespace HH\Lib\{Str, Dict};
use type Facebook\HackRouter\Tests\TestRouter;
use type Facebook\HackTest\DataProvider;
use type Usox\HackTTP\{ServerRequestFactory, UriFactory};
Expand Down Expand Up @@ -144,15 +144,33 @@ public function testMethodNotAllowedResponses(
list($responder, $_data) =
$router->routeMethodAndPath(HttpMethod::HEAD, 'getonly');
expect($responder)->toBeSame('getonly');
expect(() ==> $router->routeMethodAndPath(HttpMethod::GET, 'headonly'))->toThrow(
MethodNotAllowedException::class,
);
expect(() ==> $router->routeMethodAndPath(HttpMethod::HEAD, 'postonly'))->toThrow(
MethodNotAllowedException::class,
);
expect(() ==> $router->routeMethodAndPath(HttpMethod::GET, 'postonly'))->toThrow(
MethodNotAllowedException::class,
);

try {
$router->routeMethodAndPath(HttpMethod::GET, 'headonly');
static::fail(
Str\format('Failed asserting that %s was thrown.', MethodNotAllowedException::class)
);
} catch(MethodNotAllowedException $e) {
expect($e->getAllowedMethods())->toContain(HttpMethod::HEAD);
}

try {
$router->routeMethodAndPath(HttpMethod::HEAD, 'postonly');
static::fail(
Str\format('Failed asserting that %s was thrown.', MethodNotAllowedException::class)
);
} catch(MethodNotAllowedException $e) {
expect($e->getAllowedMethods())->toContain(HttpMethod::POST);
}

try {
$router->routeMethodAndPath(HttpMethod::GET, 'postonly');
static::fail(
Str\format('Failed asserting that %s was thrown.', MethodNotAllowedException::class)
);
} catch(MethodNotAllowedException $e) {
expect($e->getAllowedMethods())->toContain(HttpMethod::POST);
}
}

<<DataProvider('expectedMatches')>>
Expand Down

0 comments on commit 6a2ed8a

Please sign in to comment.