Skip to content

Commit

Permalink
Update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
trowski committed Aug 5, 2023
1 parent c5179df commit 5153ae2
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 16 deletions.
98 changes: 87 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# http-server-router

This package provides a routing `RequestHandler` for [Amp's HTTP server](https://github.com/amphp/http-server) based on the request URI and method based on [FastRoute](https://github.com/nikic/FastRoute).
This package provides a routing `RequestHandler` for [Amp's HTTP server](https://github.com/amphp/http-server) based on the request URI and method using [FastRoute](https://github.com/nikic/FastRoute).

## Installation

Expand All @@ -12,25 +12,93 @@ composer require amphp/http-server-router

## Usage

**`Router`** implements `RequestHandler`. Any attached `RequestHandler` and `Middleware` instances will receive any `ServerObserver` events.
**`Router`** implements `RequestHandler`, which is used by an [`HttpServer`](https://github.com/amphp/http-server#creating-an-http-server) to handle incoming requests. Incoming requests are routed by `Router` to other `RequestHandler`s based on the request path.

Routes can be defined using the `addRoute($method, $uri, $requestHandler)` method. Please read the [FastRoute documentation on how to define placeholders](https://github.com/nikic/FastRoute#defining-routes).
Routes can be defined using the `addRoute($method, $uri, $requestHandler, ...$middeware)` method.

```php
public function addRoute(
string $method,
string $uri,
RequestHandler $requestHandler,
Middleware ...$middlewares,
): void
```

Matched route arguments are available in the request attributes under the `Amp\Http\Server\Router` key as an associative array.

Middleware provided to `addRoute()` will only be applied to the given route.

Please read the [FastRoute documentation on how to define placeholders](https://github.com/nikic/FastRoute#defining-routes).

### Middleware

In addition to specifying middlewares by route with `addRoute()`, you may wrap all routes with a common set of middlware using `stackMiddleware(...$middleware)`.

```php
public function stackMiddleware(Middleware ...$middlewares): void
```

### Fallback

If no routes match a request path, you can specify another instance of `RequestHandler` which will handle any unmatched routes. If no fallback handler is provided, a 404 response will be returned using the instance of `ErrorHandler` provided to the `Router` constructor.

```php
public function setFallback(RequestHandler $requestHandler): void
```

## Example

```php
$router = new Router;
use Amp\Http\HttpStatus;
use Amp\Http\Server\DefaultErrorHandler;
use Amp\Http\Server\Request;
use Amp\Http\Server\RequestHandler\ClosureRequestHandler;
use Amp\Http\Server\Response;
use Amp\Http\Server\Router;
use Amp\Http\Server\SocketHttpServer;

$router->addRoute('GET', '/', new CallableRequestHandler(function () {
return new Response(HttpStatus::OK, ['content-type' => 'text/plain'], 'Hello, world!');
}));
// $logger is an instance of a PSR-3 logger.
$server = SocketHttpServer::createForDirectAccess($logger);
$errorHandler = new DefaultErrorHandler();

$router->addRoute('GET', '/{name}', new CallableRequestHandler(function (Request $request) {
$args = $request->getAttribute(Router::class);
return new Response(HttpStatus::OK, ['content-type' => 'text/plain'], "Hello, {$args['name']}!");
}));
$router = new Router($server, $errorHandler);

$router->addRoute('GET', '/', new ClosureRequestHandler(
function () {
return new Response(
status: HttpStatus::OK,
headers: ['content-type' => 'text/plain'],
body: 'Hello, world!',
);
},
));

$router->addRoute('GET', '/{name}', new ClosureRequestHandler(
function (Request $request) {
$args = $request->getAttribute(Router::class);
return new Response(
status: HttpStatus::OK,
headers: ['content-type' => 'text/plain'],
body: "Hello, {$args['name']}!",
);
},
));

$server->expose('0.0.0.0:1337');

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

// Serve requests until SIGINT or SIGTERM is received by the process.
Amp\trapSignal([SIGINT, SIGTERM]);

$server->stop();
```

A full example is found in [`examples/hello-world.php`](https://github.com/amphp/http-server-router/blob/2.x/examples/hello-world.php).

```bash
php examples/hello-world.php
```

## Limitations
Expand All @@ -40,3 +108,11 @@ This will also decode any forward slashes (`/`), which might result in unexpecte
FastRoute placeholders match path segments by default, which are separated by slashes.
That means a route like `/token/{token}` won't match if the token contains an encoded slash.
You can work around this limitation by using a custom regular expression for the placeholder like `/token/{token:.+}`.

## Security

If you discover any security related issues, please use the private security issue reporter instead of using the public issue tracker.

## License

The MIT License (MIT). Please see [LICENSE](./LICENSE) for more information.
10 changes: 5 additions & 5 deletions src/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Amp\Http\Server\RequestHandler\ClosureRequestHandler;
use FastRoute\Dispatcher;
use FastRoute\RouteCollector;
use function Amp\Http\Server\Middleware\stackMiddleware;
use function FastRoute\simpleDispatcher;

final class Router implements RequestHandler
Expand Down Expand Up @@ -37,8 +38,6 @@ final class Router implements RequestHandler

/**
* @param positive-int $cacheSize Maximum number of route matches to cache.
*
* @throws \Error If `$cacheSize` is less than zero.
*/
public function __construct(
HttpServer $httpServer,
Expand Down Expand Up @@ -213,7 +212,7 @@ public function addRoute(
* All middlewares are called in the order they're passed, so the first middleware is the outer middleware.
*
* On repeated calls, the later call will wrap the passed middlewares around the previous stack. This ensures a
* router can use `stack()` and then another entity can wrap a router with additional middlewares.
* router can use {@see stackMiddleware()} and then another entity can wrap a router with additional middlewares.
*
* @throws \Error If the server has started.
*/
Expand All @@ -227,9 +226,10 @@ public function stackMiddleware(Middleware ...$middlewares): void
}

/**
* Specifies an instance of RequestHandler that is used if no routes match.
* Specifies an instance of {@see RequestHandler} that is used if no routes match.
*
* If no fallback is given, a 404 response is returned from `respond()` when no matching routes are found.
* If no fallback is given, a 404 response is returned from {@see handleRequest()} when no matching routes are
* found.
*
* @throws \Error If the server has started.
*/
Expand Down

0 comments on commit 5153ae2

Please sign in to comment.