├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── Exception │ ├── InvalidRequestId.php │ ├── MissingRequestId.php │ ├── NotGenerated.php │ └── RequestIdExceptionInterface.php ├── Generator │ ├── GeneratorInterface.php │ ├── Md5Generator.php │ ├── PhpUniqidGenerator.php │ ├── PrefixedGenerator.php │ ├── RamseyUuid1Generator.php │ ├── RamseyUuid3Generator.php │ ├── RamseyUuid4Generator.php │ ├── RamseyUuid4StaticGenerator.php │ └── RamseyUuid5Generator.php ├── MonologProcessor.php ├── OverridePolicy │ └── OverridePolicyInterface.php ├── RequestDecorator.php ├── RequestIdMiddleware.php ├── RequestIdProvider.php ├── RequestIdProviderFactory.php ├── RequestIdProviderFactoryInterface.php └── RequestIdProviderInterface.php └── test ├── Generator ├── Md5GeneratorTest.php ├── PhpUniqidGeneratorTest.php ├── PrefixedGeneratorTest.php ├── RamseyFactoryUuidGeneratorTest.php └── RamseyUuid4StaticGeneratorTest.php ├── MonologProcessorTest.php ├── RequestDecoratorTest.php ├── RequestIdMiddlewareTest.php └── RequestIdProviderTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | composer.lock 3 | tmp/ 4 | phpunit-coverage-clover.xml 5 | .idea 6 | .phpunit.result.cache 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 7.1 5 | - 7.2 6 | - 7.3 7 | - 7.4 8 | - 8.0 9 | 10 | env: 11 | - DEPS=lowest 12 | - DEPS=latest 13 | 14 | before_script: 15 | - phpenv config-rm xdebug.ini 16 | - if [[ $DEPS == 'lowest' ]]; then composer update --prefer-stable --no-interaction --prefer-lowest ; fi 17 | - if [[ $DEPS == 'latest' ]]; then composer update --prefer-stable --no-interaction ; fi 18 | 19 | script: 20 | - ./vendor/bin/phpunit 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 PHP Middleware 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Request ID middleware for PHP 2 | 3 | [![Build Status](https://travis-ci.org/php-middleware/request-id.svg?branch=master)](https://travis-ci.org/php-middleware/request-id) 4 | 5 | PSR-7 Request ID middleware 6 | 7 | This middleware provide framework-agnostic possibility to generate and add to request/response's header Request ID (Correlation ID). 8 | 9 | ## Installation 10 | 11 | ```bash 12 | composer require php-middleware/request-id 13 | ``` 14 | 15 | ## Usage 16 | 17 | This middleware require in contructor `PhpMiddleware\RequestId\RequestIdProviderFactoryInterface` implementation which 18 | must create a new `RequestIdProviderInterface` object. We provide `RequestIdProvider` default implementation. 19 | 20 | ```php 21 | $generator = new PhpMiddleware\RequestId\Generator\PhpUniqidGenerator(); 22 | $requestIdProvider = new PhpMiddleware\RequestId\RequestIdProviderFactory($generator); 23 | $requestIdMiddleware = new PhpMiddleware\RequestId\RequestIdMiddleware($requestIdProvider); 24 | 25 | $app = new MiddlewareRunner(); 26 | $app->add($requestIdMiddleware); 27 | $app->run($request, $response); 28 | ``` 29 | 30 | All Provider factory constructor options: 31 | 32 | * `PhpMiddleware\RequestId\Generator\GeneratorInterface` `$generator` - generator implementation (required) 33 | * `bool|PhpMiddleware\RequestId\OverridePolicy\OverridePolicyInterface` `$allowOverride` (default `true`) - if `true` and request id header exists in incoming request, then value from request header will be used in middleware, using generator will be avoid 34 | * `string` `$requestHeader` (default `X-Request-Id`) - request header name 35 | 36 | How to get request id in my application? 37 | 38 | * Middleware implements `RequestIdProviderInterface`, so you are able to use `getRequestId()` method, 39 | * from `request-id` attribute in `ServerRequest` object (`$request->getAttribute(RequestIdMiddleware::ATTRIBUTE_NAME)`). 40 | 41 | ### Override policy 42 | 43 | You can add your own logic to decide when override incoming request id. You can implement `OverridePolicyInterface` and pass it as `$allowOverride` variable in constructor. 44 | 45 | ### Monolog processor 46 | 47 | We provide simple [Monolog](https://github.com/Seldaek/monolog) [processor](src/MonologProcessor.php) to add request it to every log entry! 48 | 49 | ### Request decorator 50 | 51 | [RequestDecorator](src/RequestDecorator.php) adds header with request id to your request object. It's useful when your microservices communicate between using PSR-7 HTTP messages e.g. [Guzzle](https://github.com/guzzle/guzzle). 52 | 53 | ### Request Id generators 54 | 55 | To generate request id you need to use implementation of `PhpMiddleware\RequestId\Generator\GeneratorInterface`. There are predefined generators in `PhpMiddleware\RequestId\Generator\` namespace: 56 | 57 | #### PhpUniqidGenerator 58 | 59 | Simple generator using [uniqid](http://php.net/manual/en/function.uniqid.php) function. 60 | 61 | #### RamseyUuid1Generator 62 | 63 | [UUID](https://tools.ietf.org/html/rfc4122)1 implementations of [Ramsey\Uuid](https://github.com/ramsey/uuid). To use it you need to add `ramsey/uuid` dependency to your `composer.json`. 64 | 65 | #### RamseyUuid3Generator 66 | 67 | [UUID](https://tools.ietf.org/html/rfc4122)3 implementations of [Ramsey\Uuid](https://github.com/ramsey/uuid). To use it you need to add `ramsey/uuid` dependency to your `composer.json`. 68 | 69 | #### RamseyUuid4Generator 70 | 71 | [UUID](https://tools.ietf.org/html/rfc4122)4 implementations of [Ramsey\Uuid](https://github.com/ramsey/uuid). To use it you need to add `ramsey/uuid` dependency to your `composer.json`. 72 | 73 | #### RamseyUuid4StaticGenerator 74 | 75 | Generates Uuid4 like `RamseyUuid4Generator` however it's not require any dependency (it use static factory method). 76 | 77 | #### RamseyUuid5Generator 78 | 79 | [UUID](https://tools.ietf.org/html/rfc4122)5 implementations of [Ramsey\Uuid](https://github.com/ramsey/uuid). To use it you need to add `ramsey/uuid` dependency to your `composer.json`. 80 | 81 | #### PrefixedGenerator 82 | 83 | It adds prefix to generated request id. 84 | 85 | #### Md5Generator 86 | 87 | This generator converts generated request id to md5 hash. 88 | 89 | ## It's just works with any modern php framework! 90 | 91 | Middleware tested on: 92 | * [Expressive](https://github.com/zendframework/zend-expressive) 93 | 94 | Middleware should works with: 95 | * [Slim 3.x](https://github.com/slimphp/Slim) 96 | 97 | And any other modern framework [supported middlewares and PSR-7](https://mwop.net/blog/2015-01-08-on-http-middleware-and-psr-7.html). 98 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "php-middleware/request-id", 3 | "description": "Request Id middleware with PSR-7", 4 | "type": "library", 5 | "license": "MIT", 6 | "keywords": [ 7 | "middleware", 8 | "psr", 9 | "psr-7", 10 | "request-id" 11 | ], 12 | "require": { 13 | "php": "^7.1 | ^8.0", 14 | "psr/http-message": "^1.0", 15 | "psr/http-server-handler": "^1.0", 16 | "psr/http-server-middleware": "^1.0" 17 | }, 18 | "require-dev": { 19 | "ramsey/uuid": "^3.9.3", 20 | "laminas/laminas-diactoros": "^2.2.1", 21 | "phpunit/phpunit": "^7.5.20 | ^8.5.8 | ^9.4.2" 22 | }, 23 | "suggest": { 24 | "ramsey/uuid": "To use Ramsey\\Uuid 3.0 generator" 25 | }, 26 | "autoload": { 27 | "psr-4": { 28 | "PhpMiddleware\\RequestId\\": "src/" 29 | } 30 | }, 31 | "autoload-dev": { 32 | "psr-4": { 33 | "PhpMiddlewareTest\\RequestId\\": "test/" 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ./test 7 | 8 | 9 | 10 | 11 | 12 | ./src 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Exception/InvalidRequestId.php: -------------------------------------------------------------------------------- 1 | generator = $generator; 12 | } 13 | 14 | public function generateRequestId(): string 15 | { 16 | return md5($this->generator->generateRequestId()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Generator/PhpUniqidGenerator.php: -------------------------------------------------------------------------------- 1 | prefix = $prefix; 16 | $this->moreEntropy = $moreEntropy; 17 | } 18 | 19 | public function generateRequestId(): string 20 | { 21 | return uniqid($this->prefix, $this->moreEntropy); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Generator/PrefixedGenerator.php: -------------------------------------------------------------------------------- 1 | prefix = $prefix; 13 | $this->generator = $generator; 14 | } 15 | 16 | public function generateRequestId(): string 17 | { 18 | return $this->prefix . $this->generator->generateRequestId(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Generator/RamseyUuid1Generator.php: -------------------------------------------------------------------------------- 1 | factory = $factory; 19 | $this->node = $node; 20 | $this->clockSeq = $clockSeq; 21 | } 22 | 23 | public function generateRequestId(): string 24 | { 25 | return $this->factory->uuid1($this->node, $this->clockSeq)->toString(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Generator/RamseyUuid3Generator.php: -------------------------------------------------------------------------------- 1 | factory = $factory; 16 | $this->ns = $ns; 17 | $this->name = $name; 18 | } 19 | 20 | public function generateRequestId(): string 21 | { 22 | return $this->factory->uuid3($this->ns, $this->name)->toString(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Generator/RamseyUuid4Generator.php: -------------------------------------------------------------------------------- 1 | factory = $factory; 14 | } 15 | 16 | public function generateRequestId(): string 17 | { 18 | return $this->factory->uuid4()->toString(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Generator/RamseyUuid4StaticGenerator.php: -------------------------------------------------------------------------------- 1 | toString(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Generator/RamseyUuid5Generator.php: -------------------------------------------------------------------------------- 1 | factory = $factory; 16 | $this->ns = $ns; 17 | $this->name = $name; 18 | } 19 | 20 | public function generateRequestId(): string 21 | { 22 | return $this->factory->uuid5($this->ns, $this->name)->toString(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/MonologProcessor.php: -------------------------------------------------------------------------------- 1 | requestIdProvider = $requestIdProvider; 16 | } 17 | 18 | public function __invoke(array $record): array 19 | { 20 | try { 21 | $requestId = $this->requestIdProvider->getRequestId(); 22 | } catch (MissingRequestId $e) { 23 | $requestId = null; 24 | } 25 | 26 | $record['extra'][self::KEY] = $requestId; 27 | 28 | return $record; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/OverridePolicy/OverridePolicyInterface.php: -------------------------------------------------------------------------------- 1 | requestIdProvider = $requestIdProvider; 15 | $this->headerName = $headerName; 16 | } 17 | 18 | /** 19 | * Adds request id to request and return new instance 20 | */ 21 | public function decorate(RequestInterface $request): RequestInterface 22 | { 23 | return $request->withHeader($this->headerName, $this->requestIdProvider->getRequestId()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/RequestIdMiddleware.php: -------------------------------------------------------------------------------- 1 | requestIdProviderFactory = $requestIdProviderFactory; 25 | $this->responseHeader = $responseHeader; 26 | } 27 | 28 | public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface 29 | { 30 | $requestWithAttribute = $this->attachRequestIdToAttribute($request); 31 | 32 | $response = $handler->handle($requestWithAttribute); 33 | 34 | return $this->attachRequestIdToResponse($response); 35 | } 36 | 37 | private function attachRequestIdToAttribute(ServerRequestInterface $request): ServerRequestInterface 38 | { 39 | $requestIdProvider = $this->requestIdProviderFactory->create($request); 40 | $this->requestId = $requestIdProvider->getRequestId(); 41 | 42 | return $request->withAttribute(self::ATTRIBUTE_NAME, $this->requestId); 43 | } 44 | 45 | private function attachRequestIdToResponse(ResponseInterface $response): ResponseInterface 46 | { 47 | if (is_string($this->responseHeader) && !empty($this->responseHeader)) { 48 | return $response->withHeader($this->responseHeader, $this->requestId); 49 | } 50 | return $response; 51 | } 52 | 53 | /** 54 | * @throws NotGenerated 55 | */ 56 | public function getRequestId(): string 57 | { 58 | if ($this->requestId === null) { 59 | throw new NotGenerated('Request id is not generated yet'); 60 | } 61 | return $this->requestId; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/RequestIdProvider.php: -------------------------------------------------------------------------------- 1 | request = $request; 32 | $this->generator = $generator; 33 | $this->allowOverride = $allowOverride; 34 | $this->requestHeader = $requestHeader; 35 | } 36 | 37 | /** 38 | * @throws RequestIdExceptionInterface 39 | */ 40 | public function getRequestId(): string 41 | { 42 | if ($this->requestId !== null) { 43 | return $this->requestId; 44 | } 45 | 46 | if ($this->isPossibleToGetFromRequest($this->request)) { 47 | $requestId = $this->request->getHeaderLine($this->requestHeader); 48 | 49 | if (empty($requestId)) { 50 | throw new MissingRequestId(sprintf('Missing request id in "%s" request header', $this->requestHeader)); 51 | } 52 | } else { 53 | $requestId = $this->generator->generateRequestId(); 54 | 55 | if (empty($requestId)) { 56 | throw new InvalidRequestId('Generator return empty value'); 57 | } 58 | if (!is_string($requestId)) { 59 | throw new InvalidRequestId('Request id is not a string'); 60 | } 61 | } 62 | $this->requestId = $requestId; 63 | 64 | return $requestId; 65 | } 66 | 67 | protected function isPossibleToGetFromRequest(ServerRequestInterface $request): bool 68 | { 69 | if ($this->allowOverride instanceof OverridePolicyInterface) { 70 | $allowOverride = $this->allowOverride->isAllowToOverride($request); 71 | } else { 72 | $allowOverride = $this->allowOverride; 73 | } 74 | 75 | return $allowOverride === true && $request->hasHeader($this->requestHeader); 76 | } 77 | } -------------------------------------------------------------------------------- /src/RequestIdProviderFactory.php: -------------------------------------------------------------------------------- 1 | generator = $generator; 27 | $this->allowOverride = $allowOverride; 28 | $this->requestHeader = $requestHeader; 29 | } 30 | 31 | public function create(ServerRequestInterface $request): RequestIdProviderInterface 32 | { 33 | return new RequestIdProvider($request, $this->generator, $this->allowOverride, $this->requestHeader); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/RequestIdProviderFactoryInterface.php: -------------------------------------------------------------------------------- 1 | createMock(GeneratorInterface::class); 16 | $decoratedGenerator->method('generateRequestId')->willReturn('boo'); 17 | 18 | $this->generator = new Md5Generator($decoratedGenerator); 19 | } 20 | 21 | public function testGetHashFromGeneratedValue() 22 | { 23 | $result = $this->generator->generateRequestId(); 24 | 25 | $this->assertSame('ae3e83e2fab3a7d8683d8eefabd1e74d', $result); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/Generator/PhpUniqidGeneratorTest.php: -------------------------------------------------------------------------------- 1 | generator = new PhpUniqidGenerator(); 15 | } 16 | 17 | public function testGetHashFromGeneratedValue() 18 | { 19 | $result = $this->generator->generateRequestId(); 20 | 21 | $this->assertNotEmpty($result); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/Generator/PrefixedGeneratorTest.php: -------------------------------------------------------------------------------- 1 | decoratedGenerator = $this->createMock(GeneratorInterface::class); 16 | $this->decoratedGenerator->method('generateRequestId')->willReturn('boo'); 17 | } 18 | 19 | public function testGetHashFromGeneratedValue() 20 | { 21 | $result = $this->getGenerator('foo_')->generateRequestId(); 22 | 23 | $this->assertSame('foo_boo', $result); 24 | } 25 | 26 | public function getGenerator($prefix) 27 | { 28 | return new PrefixedGenerator($prefix, $this->decoratedGenerator); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/Generator/RamseyFactoryUuidGeneratorTest.php: -------------------------------------------------------------------------------- 1 | factory = $this->createMock(UuidFactoryInterface::class); 21 | 22 | $this->uuid = $this->createMock(UuidInterface::class); 23 | $this->uuid->method('toString')->willReturn('uuid'); 24 | } 25 | 26 | public function testUuid1Generator() 27 | { 28 | $generator = new RamseyUuid1Generator($this->factory); 29 | $this->factory->method('uuid1')->willReturn($this->uuid); 30 | 31 | $result = $generator->generateRequestId(); 32 | 33 | $this->assertSame('uuid', $result); 34 | } 35 | 36 | public function testUuid3Generator() 37 | { 38 | $generator = new RamseyUuid3Generator($this->factory, 'ns', 'name'); 39 | $this->factory->method('uuid3')->with('ns', 'name')->willReturn($this->uuid); 40 | 41 | $result = $generator->generateRequestId(); 42 | 43 | $this->assertSame('uuid', $result); 44 | } 45 | 46 | public function testUuid4Generator() 47 | { 48 | $generator = new RamseyUuid4Generator($this->factory); 49 | $this->factory->method('uuid4')->willReturn($this->uuid); 50 | 51 | $result = $generator->generateRequestId(); 52 | 53 | $this->assertSame('uuid', $result); 54 | } 55 | 56 | public function testUuid5Generator() 57 | { 58 | $generator = new RamseyUuid5Generator($this->factory, 'ns', 'name'); 59 | $this->factory->method('uuid5')->with('ns', 'name')->willReturn($this->uuid); 60 | 61 | $result = $generator->generateRequestId(); 62 | 63 | $this->assertSame('uuid', $result); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test/Generator/RamseyUuid4StaticGeneratorTest.php: -------------------------------------------------------------------------------- 1 | generator = new RamseyUuid4StaticGenerator(); 17 | } 18 | 19 | public function testGenerateId() 20 | { 21 | $uuidString = $this->generator->generateRequestId(); 22 | 23 | $uuid = Uuid::fromString($uuidString); 24 | 25 | $this->assertInstanceOf(UuidInterface::class, $uuid); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/MonologProcessorTest.php: -------------------------------------------------------------------------------- 1 | requestIdProvider->expects($this->once())->method('getRequestId')->willReturn('boo'); 18 | $record = ['extra' => []]; 19 | 20 | $newRecord = call_user_func($this->processor, $record); 21 | 22 | $this->assertArrayHasKey(MonologProcessor::KEY, $newRecord['extra']); 23 | $this->assertSame('boo', $newRecord['extra'][MonologProcessor::KEY]); 24 | } 25 | 26 | public function testIsMissingRequestIdExceptionHandledProperly() 27 | { 28 | $this->requestIdProvider->expects($this->once())->method('getRequestId')->willThrowException(new MissingRequestId()); 29 | $record = ['extra' => []]; 30 | 31 | $newRecord = call_user_func($this->processor, $record); 32 | 33 | $this->assertArrayHasKey(MonologProcessor::KEY, $newRecord['extra']); 34 | $this->assertNull($newRecord['extra'][MonologProcessor::KEY]); 35 | } 36 | 37 | protected function setUp(): void 38 | { 39 | $this->requestIdProvider = $this->createMock(RequestIdProviderInterface::class); 40 | $this->processor = new MonologProcessor($this->requestIdProvider); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/RequestDecoratorTest.php: -------------------------------------------------------------------------------- 1 | createMock(RequestIdProviderInterface::class); 19 | $requestIdProvider->expects($this->once())->method('getRequestId')->willReturn('boo'); 20 | $this->decorator = new RequestDecorator($requestIdProvider, self::CUSTOM_HEADER_NAME); 21 | } 22 | 23 | public function testIsRequestDecorated() 24 | { 25 | $request = $this->createMock(RequestInterface::class); 26 | $request->expects($this->once())->method('withHeader')->willReturnCallback(function($name, $value) use ($request) { 27 | $this->assertSame(self::CUSTOM_HEADER_NAME, $name); 28 | $this->assertSame('boo', $value); 29 | 30 | return clone $request; 31 | }); 32 | 33 | $decoratedRequest = $this->decorator->decorate($request); 34 | 35 | $this->assertNotSame($decoratedRequest, $request); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/RequestIdMiddlewareTest.php: -------------------------------------------------------------------------------- 1 | createMock(RequestIdProviderFactoryInterface::class); 22 | $requestIdProvider = $this->createMock(RequestIdProviderInterface::class); 23 | 24 | $requestIdProviderFactory->method('create')->willReturn($requestIdProvider); 25 | $requestIdProvider->method('getRequestId')->willReturn('123456789'); 26 | 27 | $middleware = new RequestIdMiddleware($requestIdProviderFactory); 28 | $request = new ServerRequest(); 29 | 30 | $handler = new class implements RequestHandlerInterface { 31 | public function handle(ServerRequestInterface $request): ResponseInterface 32 | { 33 | return new Response(); 34 | } 35 | }; 36 | 37 | $result = $middleware->process($request, $handler); 38 | 39 | $this->assertEquals('123456789', $result->getHeaderLine(RequestIdProvider::DEFAULT_REQUEST_HEADER)); 40 | $this->assertSame('123456789', $middleware->getRequestId()); 41 | } 42 | 43 | public function testNotEmmitRequestIdToResponse() 44 | { 45 | $requestIdProviderFactory = $this->createMock(RequestIdProviderFactoryInterface::class); 46 | $requestIdProvider = $this->createMock(RequestIdProviderInterface::class); 47 | 48 | $requestIdProviderFactory->method('create')->willReturn($requestIdProvider); 49 | $requestIdProvider->method('getRequestId')->willReturn('123456789'); 50 | 51 | $middleware = new RequestIdMiddleware($requestIdProviderFactory, null); 52 | $request = new ServerRequest(); 53 | 54 | $handler = new class implements RequestHandlerInterface { 55 | public function handle(ServerRequestInterface $request): ResponseInterface 56 | { 57 | return new Response(); 58 | } 59 | }; 60 | 61 | $result = $middleware->process($request, $handler); 62 | 63 | $this->assertEquals(null, $result->getHeaderLine(RequestIdProvider::DEFAULT_REQUEST_HEADER)); 64 | $this->assertSame('123456789', $middleware->getRequestId()); 65 | } 66 | 67 | public function testTryToGetRequestIdBeforeRunMiddleware() 68 | { 69 | $requestIdProviderFactory = $this->createMock(RequestIdProviderFactoryInterface::class); 70 | 71 | $middleware = new RequestIdMiddleware($requestIdProviderFactory); 72 | 73 | $this->expectException(MissingRequestId::class); 74 | 75 | $middleware->getRequestId(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /test/RequestIdProviderTest.php: -------------------------------------------------------------------------------- 1 | generator = $this->createMock(GeneratorInterface::class); 20 | } 21 | 22 | public function testGenerateIdBecauseNotExistInHeader() 23 | { 24 | $this->generator->expects($this->once())->method('generateRequestId')->willReturn('123456789'); 25 | $request = new ServerRequest(); 26 | 27 | $provider = new RequestIdProvider($request, $this->generator); 28 | $requestId = $provider->getRequestId(); 29 | 30 | $this->assertSame('123456789',$requestId); 31 | } 32 | 33 | public function testTryToGenerateEmptyRequestId() 34 | { 35 | $this->generator->expects($this->once())->method('generateRequestId')->willReturn(''); 36 | 37 | $request = new ServerRequest(); 38 | $provider = new RequestIdProvider($request, $this->generator); 39 | 40 | $this->expectException(InvalidRequestId::class); 41 | 42 | $provider->getRequestId(); 43 | } 44 | 45 | public function testDisallowOverrideButHeaderExists() 46 | { 47 | $this->generator->expects($this->once())->method('generateRequestId')->willReturn('123456789'); 48 | $request = new ServerRequest([], [], 'https://github.com/php-middleware/request-id', 'GET', 'php://input', [RequestIdProvider::DEFAULT_REQUEST_HEADER => '987654321']); 49 | 50 | $provider = new RequestIdProvider($request, $this->generator, false); 51 | $requestId = $provider->getRequestId(); 52 | 53 | $this->assertSame('123456789', $requestId); 54 | } 55 | 56 | public function testDoNotGenerateBecouseHeaderExists() 57 | { 58 | $this->generator->expects($this->never())->method('generateRequestId'); 59 | $request = new ServerRequest([], [], 'https://github.com/php-middleware/request-id', 'GET', 'php://input', [RequestIdProvider::DEFAULT_REQUEST_HEADER => '987654321']); 60 | 61 | $provider = new RequestIdProvider($request, $this->generator); 62 | $requestId = $provider->getRequestId(); 63 | 64 | $this->assertSame('987654321', $requestId); 65 | } 66 | 67 | public function testDoNotGenerateBecauseHeaderExistsButEmpty() 68 | { 69 | $this->generator->expects($this->never())->method('generateRequestId'); 70 | $request = new ServerRequest([], [], 'https://github.com/php-middleware/request-id', 'GET', 'php://input', [RequestIdProvider::DEFAULT_REQUEST_HEADER => '']); 71 | 72 | $provider = new RequestIdProvider($request, $this->generator); 73 | 74 | $this->expectException(MissingRequestId::class); 75 | 76 | $provider->getRequestId(); 77 | } 78 | 79 | public function testOverridePolicyAllowOverride() 80 | { 81 | $this->generator->method('generateRequestId')->willReturn('123456789'); 82 | 83 | $request = new ServerRequest([], [], 'https://github.com/php-middleware/request-id', 'GET', 'php://input', [RequestIdProvider::DEFAULT_REQUEST_HEADER => '987654321']); 84 | 85 | $policy = $this->createMock(OverridePolicyInterface::class); 86 | $policy->method('isAllowToOverride')->with($request)->willReturn(true); 87 | 88 | $provider = new RequestIdProvider($request, $this->generator, $policy); 89 | $requestId = $provider->getRequestId(); 90 | 91 | $this->assertSame('987654321', $requestId); 92 | } 93 | 94 | public function testOverridePolicyDisallowOverride() 95 | { 96 | $this->generator->method('generateRequestId')->willReturn('123456789'); 97 | $request = new ServerRequest([], [], 'https://github.com/php-middleware/request-id', 'GET', 'php://input', [RequestIdProvider::DEFAULT_REQUEST_HEADER => '987654321']); 98 | 99 | $policy = $this->createMock(OverridePolicyInterface::class); 100 | $policy->method('isAllowToOverride')->with($request)->willReturn(false); 101 | 102 | $provider = new RequestIdProvider($request, $this->generator, $policy); 103 | $requestId = $provider->getRequestId(); 104 | 105 | $this->assertSame('123456789', $requestId); 106 | } 107 | 108 | public function testUseCachedValue() 109 | { 110 | $this->generator->expects($this->once())->method('generateRequestId')->willReturn('123456789'); 111 | $request = new ServerRequest(); 112 | 113 | $provider = new RequestIdProvider($request, $this->generator, false); 114 | $requestId = $provider->getRequestId(); 115 | 116 | $this->assertSame('123456789', $requestId); 117 | 118 | $requestIdAfterSecondCall = $provider->getRequestId(); 119 | 120 | $this->assertSame('123456789', $requestIdAfterSecondCall); 121 | } 122 | } 123 | --------------------------------------------------------------------------------