From fe836e281e379519b9b5c1f7b241391685b51f3c Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Wed, 15 Nov 2023 22:41:44 +0100 Subject: [PATCH] API: Add openapi endpoint to view specification --- config/routes.php | 1 + resources/api/openapi.yml | 17 ++++++++++++ src/Controllers/Api/IndexController.php | 27 +++++++++++++++---- .../Controllers/Api/IndexControllerTest.php | 20 ++++++++++++++ 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/config/routes.php b/config/routes.php index 1f27a7e6..fe313bee 100644 --- a/config/routes.php +++ b/config/routes.php @@ -118,6 +118,7 @@ $route->addGroup( function (RouteCollector $route): void { $route->addRoute(['OPTIONS'], '[/{resource:.+}]', 'Api\IndexController@options'); $route->get('', 'Api\IndexController@indexV0'); + $route->get('/openapi', 'Api\IndexController@openApiV0'); $route->get('/angeltypes', 'Api\AngelTypeController@index'); $route->get('/news', 'Api\NewsController@index'); diff --git a/resources/api/openapi.yml b/resources/api/openapi.yml index c6cdca8d..d70d3e15 100644 --- a/resources/api/openapi.yml +++ b/resources/api/openapi.yml @@ -455,3 +455,20 @@ paths: $ref: '#/components/responses/ForbiddenError' '404': $ref: '#/components/responses/NotFoundError' + + /openapi: + get: + tags: + - api + summary: Get the OpenAPI definition + responses: + '200': + description: Ok + content: + application/json: {} + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/ForbiddenError' + '404': + $ref: '#/components/responses/NotFoundError' diff --git a/src/Controllers/Api/IndexController.php b/src/Controllers/Api/IndexController.php index f5b1ee0d..2b304408 100644 --- a/src/Controllers/Api/IndexController.php +++ b/src/Controllers/Api/IndexController.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Engelsystem\Controllers\Api; +use cebe\openapi\spec\OpenApi; use Engelsystem\Http\Response; use League\OpenAPIValidation\PSR7\ValidatorBuilder as OpenApiValidatorBuilder; @@ -12,6 +13,7 @@ class IndexController extends ApiController public array $permissions = [ 'index' => 'api', 'indexV0' => 'api', + 'openApiV0' => 'api', ]; public function index(): Response @@ -26,11 +28,7 @@ class IndexController extends ApiController public function indexV0(): Response { - $openApiDefinition = app()->get('path.resources.api') . '/openapi.yml'; - $schema = (new OpenApiValidatorBuilder()) - ->fromYamlFile($openApiDefinition) - ->getResponseValidator() - ->getSchema(); + $schema = $this->getApiSpecV0(); $info = $schema->info; $paths = []; foreach ($schema->paths->getIterator() as $path => $item) { @@ -45,6 +43,16 @@ class IndexController extends ApiController ])); } + public function openApiV0(): Response + { + $schema = $this->getApiSpecV0(); + $data = $schema->getSerializableData(); + unset($data->servers[1]); + $data->servers[0]->url = url('/api/v0-beta'); + + return $this->response->withContent(json_encode($data)); + } + public function options(): Response { // Respond to browser preflight options requests @@ -68,4 +76,13 @@ class IndexController extends ApiController ->withHeader('allow', 'GET') ->withContent(json_encode(['message' => 'Method not implemented'])); } + + protected function getApiSpecV0(): OpenApi + { + $openApiDefinition = app()->get('path.resources.api') . '/openapi.yml'; + return (new OpenApiValidatorBuilder()) + ->fromYamlFile($openApiDefinition) + ->getResponseValidator() + ->getSchema(); + } } diff --git a/tests/Unit/Controllers/Api/IndexControllerTest.php b/tests/Unit/Controllers/Api/IndexControllerTest.php index 69f79996..339838a5 100644 --- a/tests/Unit/Controllers/Api/IndexControllerTest.php +++ b/tests/Unit/Controllers/Api/IndexControllerTest.php @@ -29,6 +29,7 @@ class IndexControllerTest extends ApiBaseControllerTest /** * @covers \Engelsystem\Controllers\Api\IndexController::indexV0 + * @covers \Engelsystem\Controllers\Api\IndexController::getApiSpecV0 */ public function testIndexV0(): void { @@ -43,6 +44,25 @@ class IndexControllerTest extends ApiBaseControllerTest $this->assertArrayHasKey('paths', $data); } + /** + * @covers \Engelsystem\Controllers\Api\IndexController::openApiV0 + * @covers \Engelsystem\Controllers\Api\IndexController::getApiSpecV0 + */ + public function testOpenApiV0(): void + { + $controller = new IndexController(new Response()); + + $response = $controller->openApiV0(); + $this->validateApiResponse('/openapi', 'get', $response); + + $this->assertEquals(['application/json'], $response->getHeader('content-type')); + $this->assertJson($response->getContent()); + + $data = json_decode($response->getContent(), true); + $this->assertArrayHasKey('openapi', $data); + $this->assertArrayHasKey('info', $data); + } + /** * @covers \Engelsystem\Controllers\Api\IndexController::options */