From 15b60f80e640d345e1e08b69bc8d189489fdfa4b Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 3 Jan 2022 15:12:21 -0600 Subject: [PATCH 1/4] docs: provide a chapter on adding a request ID Based on a question I answered in Slack, this provides a recipe for adding a unique request ID that can then be tracked in your logs. Signed-off-by: Matthew Weier O'Phinney --- docs/book/v4/cookbook/provide-a-request-id.md | 69 +++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 70 insertions(+) create mode 100644 docs/book/v4/cookbook/provide-a-request-id.md diff --git a/docs/book/v4/cookbook/provide-a-request-id.md b/docs/book/v4/cookbook/provide-a-request-id.md new file mode 100644 index 00000000..5684f554 --- /dev/null +++ b/docs/book/v4/cookbook/provide-a-request-id.md @@ -0,0 +1,69 @@ +# Provide a unique ID in your request + +## The problem + +You want a request-specific identifier via an HTTP request header for purposes of logging, tracking, etc. +If you add it via middleware, however, it is not present in your access logs. + +## The solution + +Request identifiers are usually generated at the web-server level. +When you use a dedicated web servers such as Apache or nginx, a load balancer, or a reverse proxy, these can be configured to create and inject a request ID before it reaches your application. +However, when using mezzio-swoole, the request handler runner we create is your web server. +It has listeners that take care of logging, which means that the request generated must _already_ have the identifier if you want to be able to log it. + +This poses a problem: normally you will use middleware to propagate changes to the request. +How can you do it at the Swoole web server level? + +The answer is deceptively simple: you can provide a [delegator factory](https://docs.mezzio.dev/mezzio/v3/features/container/delegator-factories/) for decorator on thethe service that converts the Swoole HTTP request instance into the equivalent [PSR-7](https://www.php-fig.org/psr/psr-7/) HTTP request instance that is then passed to your application. + +mezzio-swoole maps the `Psr\Http\Message\ServerRequestInterface` service to its `Mezzio\Swoole\ServerRequestSwooleFactory`. +That factory returns a _callable_ that accepts a `Swoole\HTTP\Request` instance and returns a `Psr\Http\Message\ServerRequestInterface` instance. +As such, your delegator factory will need to return a callable with the same signature. + +In the following example, we use [ramsey/uuid](https://uuid.ramsey.dev/) to generate a unique request ID, and add it to an `X-Request-ID` header when returning the request. + +```php +// In your App module's top-level source directory + +declare(strict_types=1); + +namespace App; + +use Psr\Container\ContainerInterface; +use Psr\Http\Message\ServerRequestInterface; +use Ramsey\Uuid\Uuid; +use Swoole\Http\Request as SwooleHttpRequest; + +class ServerRequestIdDecorator +{ + public function __invoke(ContainerInterface $container, string $serviceName, callable $factory): callable + { + return static function (SwooleHttpRequest $swooleRequest) use ($factory): ServerRequestInterface { + $request = $factory($swooleRequest); + return $request->withHeader('X-Request-ID', Uuid::uuid1()); + }; + } +} +``` + +Then, in our App module's `ConfigProvider`, we would modify the dependency configuration to add the following: + +```php + public function getDependencies(): array + { + return [ + 'delegators' => [ + \Psr\Http\Message\ServerRequestInterface::class => [ + ServerRequestIdDecorator::class, + ], + ], + ]; + } +``` + +This approach: + +- Keeps the logic close to the web server. +- Utilizes facilities already built-in to Mezzio and mezzio-swoole. +- Allows other code to perform similar work in order to manipulate and modify the request. diff --git a/mkdocs.yml b/mkdocs.yml index 7637ea6b..042e5d70 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -25,6 +25,7 @@ nav: - Cookbook: - "Removing the StaticResourceRequestListener": v4/cookbook/static-resource-listener-removal.md - "Swoole-based server always returns home page": v4/cookbook/swoole-not-starting.md + - "Provide a unique ID in your request": v4/cookbook/provide-a-request-id.md - Migration: v4/migration.md - v3: - Introduction: v3/intro.md From 58983b116bb18cfa359460d37db65bd778a179ec Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Tue, 4 Jan 2022 08:27:15 -0600 Subject: [PATCH 2/4] fix: duplicate "the" Signed-off-by: Matthew Weier O'Phinney --- docs/book/v4/cookbook/provide-a-request-id.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/book/v4/cookbook/provide-a-request-id.md b/docs/book/v4/cookbook/provide-a-request-id.md index 5684f554..f546e03e 100644 --- a/docs/book/v4/cookbook/provide-a-request-id.md +++ b/docs/book/v4/cookbook/provide-a-request-id.md @@ -15,7 +15,7 @@ It has listeners that take care of logging, which means that the request generat This poses a problem: normally you will use middleware to propagate changes to the request. How can you do it at the Swoole web server level? -The answer is deceptively simple: you can provide a [delegator factory](https://docs.mezzio.dev/mezzio/v3/features/container/delegator-factories/) for decorator on thethe service that converts the Swoole HTTP request instance into the equivalent [PSR-7](https://www.php-fig.org/psr/psr-7/) HTTP request instance that is then passed to your application. +The answer is deceptively simple: you can provide a [delegator factory](https://docs.mezzio.dev/mezzio/v3/features/container/delegator-factories/) for decorator on the service that converts the Swoole HTTP request instance into the equivalent [PSR-7](https://www.php-fig.org/psr/psr-7/) HTTP request instance that is then passed to your application. mezzio-swoole maps the `Psr\Http\Message\ServerRequestInterface` service to its `Mezzio\Swoole\ServerRequestSwooleFactory`. That factory returns a _callable_ that accepts a `Swoole\HTTP\Request` instance and returns a `Psr\Http\Message\ServerRequestInterface` instance. From e386830c6b88c2d81b18e303f592dce025a093e5 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Tue, 4 Jan 2022 09:13:24 -0600 Subject: [PATCH 3/4] docs: incorporate feedback - Move description of the problem... under the heading marked "The problem". - Remove "simple" verbiage. Signed-off-by: Matthew Weier O'Phinney --- docs/book/v4/cookbook/provide-a-request-id.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/book/v4/cookbook/provide-a-request-id.md b/docs/book/v4/cookbook/provide-a-request-id.md index f546e03e..ca90d2e8 100644 --- a/docs/book/v4/cookbook/provide-a-request-id.md +++ b/docs/book/v4/cookbook/provide-a-request-id.md @@ -5,8 +5,6 @@ You want a request-specific identifier via an HTTP request header for purposes of logging, tracking, etc. If you add it via middleware, however, it is not present in your access logs. -## The solution - Request identifiers are usually generated at the web-server level. When you use a dedicated web servers such as Apache or nginx, a load balancer, or a reverse proxy, these can be configured to create and inject a request ID before it reaches your application. However, when using mezzio-swoole, the request handler runner we create is your web server. @@ -15,7 +13,9 @@ It has listeners that take care of logging, which means that the request generat This poses a problem: normally you will use middleware to propagate changes to the request. How can you do it at the Swoole web server level? -The answer is deceptively simple: you can provide a [delegator factory](https://docs.mezzio.dev/mezzio/v3/features/container/delegator-factories/) for decorator on the service that converts the Swoole HTTP request instance into the equivalent [PSR-7](https://www.php-fig.org/psr/psr-7/) HTTP request instance that is then passed to your application. +## The solution + +The answer is to provide a [delegator factory](https://docs.mezzio.dev/mezzio/v3/features/container/delegator-factories/) for decorator on the service that converts the Swoole HTTP request instance into the equivalent [PSR-7](https://www.php-fig.org/psr/psr-7/) HTTP request instance that is then passed to your application. mezzio-swoole maps the `Psr\Http\Message\ServerRequestInterface` service to its `Mezzio\Swoole\ServerRequestSwooleFactory`. That factory returns a _callable_ that accepts a `Swoole\HTTP\Request` instance and returns a `Psr\Http\Message\ServerRequestInterface` instance. From 5169788ecc94a5724f97fc75d0d9c5b2b837cd6c Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Wed, 5 Jan 2022 15:36:47 -0600 Subject: [PATCH 4/4] docs: fix grammar, use arrow functions Performs one more editing pass, identifying several grammatical and/or spelling errors. Also updates the example to use an arrow function. Signed-off-by: Matthew Weier O'Phinney --- docs/book/v4/cookbook/provide-a-request-id.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/book/v4/cookbook/provide-a-request-id.md b/docs/book/v4/cookbook/provide-a-request-id.md index ca90d2e8..7c1eb51b 100644 --- a/docs/book/v4/cookbook/provide-a-request-id.md +++ b/docs/book/v4/cookbook/provide-a-request-id.md @@ -6,8 +6,8 @@ You want a request-specific identifier via an HTTP request header for purposes o If you add it via middleware, however, it is not present in your access logs. Request identifiers are usually generated at the web-server level. -When you use a dedicated web servers such as Apache or nginx, a load balancer, or a reverse proxy, these can be configured to create and inject a request ID before it reaches your application. -However, when using mezzio-swoole, the request handler runner we create is your web server. +When you use dedicated web servers such as Apache or nginx, a load balancer, or a reverse proxy, these can be configured to create and inject a request ID before it reaches your application. +However, when using mezzio-swoole, the request handler runner we create **is** your web server. It has listeners that take care of logging, which means that the request generated must _already_ have the identifier if you want to be able to log it. This poses a problem: normally you will use middleware to propagate changes to the request. @@ -15,7 +15,7 @@ How can you do it at the Swoole web server level? ## The solution -The answer is to provide a [delegator factory](https://docs.mezzio.dev/mezzio/v3/features/container/delegator-factories/) for decorator on the service that converts the Swoole HTTP request instance into the equivalent [PSR-7](https://www.php-fig.org/psr/psr-7/) HTTP request instance that is then passed to your application. +The answer is to provide a [delegator factory](https://docs.mezzio.dev/mezzio/v3/features/container/delegator-factories/) on the service that converts the Swoole HTTP request instance into the equivalent [PSR-7](https://www.php-fig.org/psr/psr-7/) HTTP request instance that is then passed to your application. mezzio-swoole maps the `Psr\Http\Message\ServerRequestInterface` service to its `Mezzio\Swoole\ServerRequestSwooleFactory`. That factory returns a _callable_ that accepts a `Swoole\HTTP\Request` instance and returns a `Psr\Http\Message\ServerRequestInterface` instance. @@ -39,10 +39,8 @@ class ServerRequestIdDecorator { public function __invoke(ContainerInterface $container, string $serviceName, callable $factory): callable { - return static function (SwooleHttpRequest $swooleRequest) use ($factory): ServerRequestInterface { - $request = $factory($swooleRequest); - return $request->withHeader('X-Request-ID', Uuid::uuid1()); - }; + return static fn (SwooleHttpRequest $swooleRequest): ServerRequestInterface => $factory($swooleRequest) + ->withHeader('X-Request-ID', Uuid::uuid1()); } } ```