diff --git a/module/Rest/src/ConfigProvider.php b/module/Rest/src/ConfigProvider.php index 98ad8b4c..570eab85 100644 --- a/module/Rest/src/ConfigProvider.php +++ b/module/Rest/src/ConfigProvider.php @@ -6,6 +6,8 @@ namespace Shlinkio\Shlink\Rest; use Closure; +use function Functional\first; +use function Functional\map; use function Shlinkio\Shlink\Common\loadConfigFromGlob; use function sprintf; @@ -30,21 +32,33 @@ class ConfigProvider private function applyRoutesPrefix(array $config): array { - $routes =& $config['routes'] ?? []; + $routes = $config['routes'] ?? []; + $healthRoute = $this->buildUnversionedHealthRouteFromExistingRoutes($routes); - // Prepend the routes prefix to every path - foreach ($routes as $key => $route) { + $prefixRoute = static function (array $route) { ['path' => $path] = $route; - $routes[$key]['path'] = sprintf('%s%s', self::ROUTES_PREFIX, $path); + $route['path'] = sprintf('%s%s', self::ROUTES_PREFIX, $path); - // Also append the health route so that it works without version - if ($path === '/health') { - $route['path'] = sprintf('%s%s', self::UNVERSIONED_ROUTES_PREFIX, $path); - $route['name'] = self::UNVERSIONED_HEALTH_ENDPOINT_NAME; - $routes[] = $route; - } - } + return $route; + }; + $prefixedRoutes = map($routes, $prefixRoute); + + $config['routes'] = $healthRoute !== null ? [...$prefixedRoutes, $healthRoute] : $prefixedRoutes; return $config; } + + private function buildUnversionedHealthRouteFromExistingRoutes(array $routes): ?array + { + $healthRoute = first($routes, fn (array $route) => $route['path'] === '/health'); + if ($healthRoute === null) { + return null; + } + + $path = $healthRoute['path']; + $healthRoute['path'] = sprintf('%s%s', self::UNVERSIONED_ROUTES_PREFIX, $path); + $healthRoute['name'] = self::UNVERSIONED_HEALTH_ENDPOINT_NAME; + + return $healthRoute; + } } diff --git a/module/Rest/test/ConfigProviderTest.php b/module/Rest/test/ConfigProviderTest.php index 48c71716..8032a854 100644 --- a/module/Rest/test/ConfigProviderTest.php +++ b/module/Rest/test/ConfigProviderTest.php @@ -25,26 +25,47 @@ class ConfigProviderTest extends TestCase $this->assertArrayHasKey('dependencies', $config); } - /** @test */ - public function routesAreProperlyPrefixed(): void + /** + * @test + * @dataProvider provideRoutesConfig + */ + public function routesAreProperlyPrefixed(array $routes, array $expected): void { - $configProvider = new ConfigProvider(fn () => [ - 'routes' => [ + $configProvider = new ConfigProvider(fn () => ['routes' => $routes]); + + $config = $configProvider(); + + $this->assertEquals($expected, $config['routes']); + } + + public function provideRoutesConfig(): iterable + { + yield 'health action present' => [ + [ ['path' => '/foo'], ['path' => '/bar'], ['path' => '/baz/foo'], ['path' => '/health'], ], - ]); - - $config = $configProvider(); - - $this->assertEquals([ - ['path' => '/rest/v{version:1|2}/foo'], - ['path' => '/rest/v{version:1|2}/bar'], - ['path' => '/rest/v{version:1|2}/baz/foo'], - ['path' => '/rest/v{version:1|2}/health'], - ['path' => '/rest/health', 'name' => ConfigProvider::UNVERSIONED_HEALTH_ENDPOINT_NAME], - ], $config['routes']); + [ + ['path' => '/rest/v{version:1|2}/foo'], + ['path' => '/rest/v{version:1|2}/bar'], + ['path' => '/rest/v{version:1|2}/baz/foo'], + ['path' => '/rest/v{version:1|2}/health'], + ['path' => '/rest/health', 'name' => ConfigProvider::UNVERSIONED_HEALTH_ENDPOINT_NAME], + ], + ]; + yield 'health action not present' => [ + [ + ['path' => '/foo'], + ['path' => '/bar'], + ['path' => '/baz/foo'], + ], + [ + ['path' => '/rest/v{version:1|2}/foo'], + ['path' => '/rest/v{version:1|2}/bar'], + ['path' => '/rest/v{version:1|2}/baz/foo'], + ], + ]; } }