Skip to content

Commit 1f82315

Browse files
committed
fix(ui): resolve Swagger UI initialization and spec detection
- Fix ReferenceError: SwaggerUIStandalonePreset is correctly named - Implement dynamic spec URL detection (JSON/YAML) for Swagger UI - Ensure specHandler serves correct Content-Type based on requested route - Update acceptance tests to use public/index.php as router script - Add SwaggerUICest and enhance JsonSpecCest for better coverage - Update Dockerfile and compose.yml with correct image and paths
1 parent 48f4c01 commit 1f82315

9 files changed

Lines changed: 91 additions & 28 deletions

File tree

Dockerfile

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,4 @@ COPY --from=composer_build /app/vendor /app/vendor
4444
COPY . /app
4545

4646
# Set default environment variables
47-
ENV OPENAPI_SPEC=data/openapi.yaml
48-
49-
# Expose port 80
50-
EXPOSE 80
47+
ENV OPENAPI_SPEC=/app/data/openapi.yaml

compose.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ services:
33
build:
44
context: .
55
dockerfile: Dockerfile
6-
image: webproject/php-openapi-mock-server:latest
6+
image: ghcr.io/webproject-xyz/php-openapi-mock-server:latest
77
container_name: openapi-mock-server
88
restart: unless-stopped
99
ports:
@@ -12,9 +12,9 @@ services:
1212
# Path or URL to the OpenAPI specification
1313
- OPENAPI_SPEC=${OPENAPI_SPEC:-data/openapi.yaml}
1414
# Enable FrankenPHP watcher for hot-reload
15-
- FRANKENPHP_WATCHER=1
16-
volumes:
17-
# Mount source code for hot-reload
18-
- .:/app
19-
# Map data if you want to use local spec files
20-
- ./data:/app/data:ro
15+
# - FRANKENPHP_WATCHER=1
16+
# volumes:
17+
# # Mount source code for hot-reload
18+
# - .:/app
19+
# # Map data if you want to use local spec files
20+
# - ./data:/app/data:ro

config/routes.php

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,23 @@
2525

2626
$specHandler = static function (ServerRequestInterface $serverRequest) use ($specPath): ResponseInterface {
2727
try {
28-
$path = $specPath;
28+
$path = (string) $specPath;
2929

30-
if (str_starts_with((string) $path, 'http')) {
30+
if (str_starts_with($path, 'http')) {
3131
$content = file_get_contents($path, false, RemoteSpecificationLoader::createStreamContext());
3232
} else {
33-
$content = file_exists((string) $path) ? file_get_contents((string) $path) : null;
33+
$content = file_exists($path) ? file_get_contents($path) : null;
3434
}
3535

3636
if ($content === false || $content === null) {
3737
return new TextResponse('OpenAPI spec not found at ' . $path, 404);
3838
}
3939

40-
$contentType = str_ends_with((string) $path, '.json') ? 'application/json' : 'text/yaml';
41-
if (str_ends_with($serverRequest->getUri()->getPath(), '.json')) {
42-
$contentType = 'application/json';
43-
}
40+
$requestedPath = $serverRequest->getUri()->getPath();
41+
$isJsonRequest = str_ends_with($requestedPath, '.json');
42+
43+
// Serve the correct Content-Type for the requested route.
44+
$contentType = $isJsonRequest ? 'application/json' : 'text/yaml';
4445

4546
return new TextResponse($content, 200, [
4647
'Content-Type' => $contentType,
@@ -50,9 +51,9 @@
5051
}
5152
};
5253

53-
// Route to serve the raw OpenAPI specification
54-
$application->get('/openapi.yaml', $specHandler);
55-
$application->get('/openapi.json', $specHandler);
54+
// Route registrations
55+
$application->get('/openapi.yaml', $specHandler, 'openapi_yaml');
56+
$application->get('/openapi.json', $specHandler, 'openapi_json');
5657

5758
// Swagger UI at root
5859
$application->get('/', static function (ServerRequestInterface $serverRequest) use ($specPath): ResponseInterface {
@@ -65,6 +66,12 @@
6566
]);
6667
}
6768

69+
// Determine the correct spec URL for Swagger UI
70+
$path = (string) $specPath;
71+
$parsedPath = parse_url($path, PHP_URL_PATH) ?: $path;
72+
$extension = strtolower(pathinfo($parsedPath, PATHINFO_EXTENSION));
73+
$specUrl = $extension === 'json' ? '/openapi.json' : '/openapi.yaml';
74+
6875
$html = <<<HTML
6976
<!DOCTYPE html>
7077
<html lang="en">
@@ -87,12 +94,12 @@
8794
<script>
8895
window.onload = () => {
8996
window.ui = SwaggerUIBundle({
90-
url: '/openapi.yaml',
97+
url: '$specUrl',
9198
dom_id: '#swagger-ui',
9299
deepLinking: true,
93100
presets: [
94101
SwaggerUIBundle.presets.apis,
95-
SwaggerStandalonePreset
102+
SwaggerUIStandalonePreset
96103
],
97104
plugins: [
98105
SwaggerUIBundle.plugins.DownloadUrl
@@ -105,5 +112,5 @@
105112
</html>
106113
HTML;
107114
return new HtmlResponse($html);
108-
});
115+
}, 'home');
109116
};

tests/Acceptance.suite.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ coverage:
1212
extensions:
1313
enabled:
1414
- Codeception\Extension\RunProcess:
15-
- php -S localhost:8080 -t public
15+
- php -S localhost:8080 -t public public/index.php

tests/Acceptance/SwaggerUICest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace WebProject\PhpOpenApiMockServer\Tests\Acceptance;
5+
6+
use WebProject\PhpOpenApiMockServer\Tests\Support\AcceptanceTester;
7+
8+
class SwaggerUICest
9+
{
10+
public function _before(AcceptanceTester $I): void
11+
{
12+
// Give the built-in server some time to start on the first test
13+
static $started = false;
14+
if (!$started) {
15+
usleep(1000000); // 1.0 second
16+
$started = true;
17+
}
18+
}
19+
20+
public function testSwaggerUIHome(AcceptanceTester $I): void
21+
{
22+
$I->sendGet('/');
23+
$I->seeResponseCodeIs(200);
24+
$I->seeResponseContains('<title>OpenAPI Mock Server - Swagger UI</title>');
25+
$I->seeResponseContains('swagger-ui-bundle.js');
26+
$I->seeResponseContains('SwaggerUIStandalonePreset');
27+
}
28+
29+
public function testSwaggerUISpecUrl(AcceptanceTester $I): void
30+
{
31+
// Default is yaml
32+
$I->sendGet('/');
33+
$I->seeResponseContains("url: '/openapi.yaml'");
34+
}
35+
36+
public function testOpenApiYamlRoute(AcceptanceTester $I): void
37+
{
38+
$I->sendGet('/openapi.yaml');
39+
$I->seeResponseCodeIs(200);
40+
// Should contain some YAML-like content (default spec)
41+
$I->seeResponseContains('openapi: 3.0.0');
42+
$I->seeHttpHeader('Content-Type', 'text/yaml;charset=UTF-8');
43+
}
44+
}

tests/FailureAcceptance.suite.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ coverage:
1212
extensions:
1313
enabled:
1414
- Codeception\Extension\RunProcess:
15-
- OPENAPI_SPEC=https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/non-existent.yaml php -S localhost:8083 -t public
15+
- OPENAPI_SPEC=https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/non-existent.yaml php -S localhost:8083 -t public public/index.php

tests/JsonAcceptance.suite.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ coverage:
1212
extensions:
1313
enabled:
1414
- Codeception\Extension\RunProcess:
15-
- OPENAPI_SPEC=data/openapi.json php -S localhost:8081 -t public
15+
- OPENAPI_SPEC=data/openapi.json php -S localhost:8081 -t public public/index.php

tests/JsonAcceptance/JsonSpecCest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,19 @@ public function testGetProductsFromJsonSpec(AcceptanceTester $acceptanceTester):
2626
$response = json_decode($acceptanceTester->grabResponse(), true);
2727
$acceptanceTester->assertIsArray($response);
2828
}
29+
30+
public function testSwaggerUIPointsToJson(AcceptanceTester $acceptanceTester): void
31+
{
32+
$acceptanceTester->sendGet('/');
33+
$acceptanceTester->seeResponseCodeIs(200);
34+
$acceptanceTester->seeResponseContains("url: '/openapi.json'");
35+
}
36+
37+
public function testOpenApiJsonRoute(AcceptanceTester $acceptanceTester): void
38+
{
39+
$acceptanceTester->sendGet('/openapi.json');
40+
$acceptanceTester->seeResponseCodeIs(200);
41+
$acceptanceTester->seeHttpHeader('Content-Type', 'application/json');
42+
$acceptanceTester->seeResponseContains('"openapi": "3.0.0"');
43+
}
2944
}

tests/RemoteAcceptance.suite.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ coverage:
1212
extensions:
1313
enabled:
1414
- Codeception\Extension\RunProcess:
15-
- OPENAPI_SPEC=https://raw.githubusercontent.com/Redocly/openapi-template/gh-pages/openapi.yaml php -S localhost:8082 -t public
15+
- OPENAPI_SPEC=https://raw.githubusercontent.com/Redocly/openapi-template/gh-pages/openapi.yaml php -S localhost:8082 -t public public/index.php

0 commit comments

Comments
 (0)