From 4097948678757c59c080b3ee63783934620e78aa Mon Sep 17 00:00:00 2001 From: Darius Matulionis Date: Wed, 28 Mar 2018 15:14:37 +0300 Subject: [PATCH] OpenApi 3.0 support. closes #41 (#48) --- .travis.yml | 17 +-- README.md | 22 +++- composer.json | 10 +- config/swagger-lume.php | 21 +++- src/Generator.php | 31 +---- src/SecurityDefinitions.php | 99 +++++++++++++++ tests/CommandsTest.php | 2 +- tests/GeneratorTest.php | 36 +----- tests/LumenTestCase.php | 14 ++- tests/SecurityDefinitionsTest.php | 76 +++++++++++ .../annotations/OpenApi/Anotations.php | 119 ++++++++++++++++++ .../Anotations.php} | 7 +- 12 files changed, 372 insertions(+), 82 deletions(-) create mode 100644 src/SecurityDefinitions.php create mode 100644 tests/SecurityDefinitionsTest.php create mode 100644 tests/storage/annotations/OpenApi/Anotations.php rename tests/storage/annotations/{ApiAnotationsExample.php => Swagger/Anotations.php} (94%) diff --git a/.travis.yml b/.travis.yml index 5a1d1a2..dfc5a9d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,19 +6,25 @@ env: global: - DEFAULT_COMPOSER_FLAGS="--no-interaction --no-progress --optimize-autoloader" - REPORT_TESTS_COVERAGE=0 + - SWAGGER_VERSION=2.0 matrix: fast_finish: true include: - - php: 7.0 - php: 7.1 - env: REPORT_TESTS_COVERAGE=1 + env: CACHE_NAME=SWAGGER + - php: 7.1 + env: SWAGGER_VERSION=3.0 CACHE_NAME=OPEN_API + - php: 7.2 + env: REPORT_TESTS_COVERAGE=1 CACHE_NAME=SWAGGER + - php: 7.2 + env: SWAGGER_VERSION=3.0 CACHE_NAME=OPEN_API cache: directories: - "$HOME/.composer/cache" -before_install: - - travis_retry composer global require $DEFAULT_COMPOSER_FLAGS hirak/prestissimo install: - travis_retry composer update $DEFAULT_COMPOSER_FLAGS + - if [ $SWAGGER_VERSION == 2.0 ]; then composer require 'zircote/swagger-php:2.*'; fi + - if [ $SWAGGER_VERSION == 3.0 ]; then composer require 'zircote/swagger-php:3.*'; fi - composer info -D | sort before_script: - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter @@ -30,9 +36,6 @@ script: after_success: - if [ $REPORT_TESTS_COVERAGE == 1 ] && [ $TRAVIS_PULL_REQUEST == "false" ]; then ./cc-test-reporter after-build -t clover --exit-code $TRAVIS_TEST_RESULT; fi - if [ $REPORT_TESTS_COVERAGE == 1 ]; then php vendor/bin/coveralls -v; fi -#addons: -# code_climate: -# repo_token: CODECLIMATE_REPO_TOKEN notifications: email: false slack: diff --git a/README.md b/README.md index 06fcf12..2b74dfa 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,10 @@ Installation 5.4.x | 2.2 | 1.1, 1.2, 2.0 | ``` composer require "darkaonline/swagger-lume:~2.0" ``` 5.4.x | 3 | 2.0 | ``` composer require "darkaonline/swagger-lume:~3.0" ``` 5.5.x | 3 | 2.0 | ``` composer require "darkaonline/swagger-lume:5.5.*" ``` + 5.6.x | 3 | 2.0, 3.0 | ``` composer require "darkaonline/swagger-lume:5.6.*" ``` -- Open your `bootstrap/app.php` file and: +- Open your `bootstrap/app.php` file and: uncomment this line (around line 26) in `Create The Application` section: ```php @@ -41,9 +42,26 @@ add this line in `Register Service Providers` section: - Run `php artisan swagger-lume:publish-config` to publish configs (`config/swagger-lume.php`) -- Make configuration changes if needed +- Make configuration changes if needed - Run `php artisan swagger-lume:publish` to publish everything +Using [OpenApi 3.0 Specification](https://github.com/OAI/OpenAPI-Specification) +============ +If you would like to use lattes OpenApi specifications (originally known as the Swagger Specification) in you project you should: +- Explicitly require `swagger-php` version 3.* in your projects composer by running: +```bash +composer require 'zircote/swagger-php:3.*' +``` +- Set environment variable `SWAGGER_VERSION` to **3.0** in your `.env` file: +``` +SWAGGER_VERSION=3.0 +``` +or in your `config/l5-swagger.php`: +```php +'swagger_version' => env('SWAGGER_VERSION', '3.0'), +``` +- Use examples provided here: https://github.com/zircote/swagger-php/tree/3.x/Examples/petstore-3.0 + Configuration ============ - Run `php artisan swagger-lume:publish-config` to publish configs (`config/swagger-lume.php`) diff --git a/composer.json b/composer.json index 633fa4c..d29cfd1 100644 --- a/composer.json +++ b/composer.json @@ -10,13 +10,15 @@ } ], "require": { - "php": ">=5.6.4", - "laravel/lumen-framework": "~5.5", - "zircote/swagger-php": "~2.0", + "php": ">=7.1.3", + "laravel/lumen-framework": "~5.6", + "zircote/swagger-php": "3.*", "swagger-api/swagger-ui": "^3.0" }, "require-dev": { - "phpunit/phpunit": "~5.7", + "fzaninotto/faker": "~1.4", + "phpunit/phpunit": "~7.0", + "mockery/mockery": "~1.0", "satooshi/php-coveralls": "^2.0" }, "autoload": { diff --git a/config/swagger-lume.php b/config/swagger-lume.php index c275220..387d42d 100644 --- a/config/swagger-lume.php +++ b/config/swagger-lume.php @@ -1,7 +1,6 @@ [ /* |-------------------------------------------------------------------------- @@ -126,6 +125,23 @@ 'write:projects' => 'modify projects in your account', ] ],*/ + + /* Open API 3.0 support + 'passport' => [ // Unique name of security + 'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'Laravel passport oauth2 security.', + 'in' => 'header', + 'scheme' => 'https', + 'flows' => [ + "password" => [ + "authorizationUrl" => config('app.url') . '/oauth/authorize', + "tokenUrl" => config('app.url') . '/oauth/token', + "refreshUrl" => config('app.url') . '/token/refresh', + "scopes" => [] + ], + ], + ], + */ ], /* @@ -140,7 +156,7 @@ | Edit to set the swagger version number |-------------------------------------------------------------------------- */ - 'swagger_version' => env('SWAGGER_VERSION', '2.0'), + 'swagger_version' => env('SWAGGER_VERSION', '3.0'), /* |-------------------------------------------------------------------------- @@ -185,5 +201,4 @@ 'constants' => [ // 'SWAGGER_LUME_CONST_HOST' => env('SWAGGER_LUME_CONST_HOST', 'http://my-default-host.com'), ], - ]; diff --git a/src/Generator.php b/src/Generator.php index 791e754..d699f7c 100644 --- a/src/Generator.php +++ b/src/Generator.php @@ -29,7 +29,8 @@ public static function generateDocs() $filename = $docDir.'/'.config('swagger-lume.paths.docs_json'); $swagger->saveAs($filename); - self::appendSecurityDefinitions($filename); + $security = new SecurityDefinitions(); + $security->generate($filename); } } @@ -41,32 +42,4 @@ protected static function defineConstants(array $constants) } } } - - protected static function appendSecurityDefinitions($filename) - { - $securityConfig = config('swagger-lume.security', []); - - if (is_array($securityConfig) && ! empty($securityConfig)) { - $documentation = collect( - json_decode(file_get_contents($filename)) - ); - - $securityDefinitions = $documentation->has('securityDefinitions') ? - collect($documentation->get('securityDefinitions')) : - collect(); - - foreach ($securityConfig as $key => $cfg) { - $securityDefinitions->offsetSet($key, self::arrayToObject($cfg)); - } - - $documentation->offsetSet('securityDefinitions', $securityDefinitions); - - file_put_contents($filename, $documentation->toJson()); - } - } - - public static function arrayToObject($array) - { - return json_decode(json_encode($array)); - } } diff --git a/src/SecurityDefinitions.php b/src/SecurityDefinitions.php new file mode 100644 index 0000000..c06874f --- /dev/null +++ b/src/SecurityDefinitions.php @@ -0,0 +1,99 @@ +='); + + $documentation = $openApi3 ? + $this->generateOpenApi($documentation, $securityConfig) : + $this->generateSwaggerApi($documentation, $securityConfig); + + file_put_contents($filename, $documentation->toJson()); + } + } + + /** + * Inject security settings for Swagger 1 & 2. + * + * @param Collection $documentation The parse json + * @param array $securityConfig The security settings from l5-swagger + * + * @return Collection + */ + public function generateSwaggerApi(Collection $documentation, array $securityConfig) + { + $securityDefinitions = collect(); + if ($documentation->has('securityDefinitions')) { + $securityDefinitions = collect($documentation->get('securityDefinitions')); + } + + foreach ($securityConfig as $key => $cfg) { + $securityDefinitions->offsetSet($key, self::arrayToObject($cfg)); + } + + $documentation->offsetSet('securityDefinitions', $securityDefinitions); + + return $documentation; + } + + /** + * Inject security settings for OpenApi 3. + * + * @param Collection $documentation The parse json + * @param array $securityConfig The security settings from l5-swagger + * + * @return Collection + */ + public function generateOpenApi(Collection $documentation, array $securityConfig) + { + $components = collect(); + if ($documentation->has('components')) { + $components = collect($documentation->get('components')); + } + + $securitySchemes = collect(); + if ($components->has('securitySchemes')) { + $securitySchemes = collect($components->get('securitySchemes')); + } + + foreach ($securityConfig as $key => $cfg) { + $securitySchemes->offsetSet($key, self::arrayToObject($cfg)); + } + + $components->offsetSet('securitySchemes', $securitySchemes); + + $documentation->offsetSet('components', $components); + + return $documentation; + } + + /** + * Converts an array to an object. + * + * @param $array + * + * @return object + */ + public static function arrayToObject($array) + { + return json_decode(json_encode($array)); + } +} diff --git a/tests/CommandsTest.php b/tests/CommandsTest.php index 3df795f..cec1c81 100644 --- a/tests/CommandsTest.php +++ b/tests/CommandsTest.php @@ -24,7 +24,7 @@ public function canGenerateJsonDocumentation() $fileContent = file_get_contents($this->jsonDocsFile()); $this->assertJson($fileContent); - $this->assertContains('Swagger Lume API', $fileContent); + $this->assertContains('SwaggerLume', $fileContent); //Check if constants are replaced $this->assertContains('http://my-default-host.com', $fileContent); diff --git a/tests/GeneratorTest.php b/tests/GeneratorTest.php index 63fbb7b..b02c2df 100644 --- a/tests/GeneratorTest.php +++ b/tests/GeneratorTest.php @@ -19,13 +19,17 @@ public function canGenerateApiJsonFile() $this->assertResponseOk(); - $this->assertContains('Swagger Lume API', $response->response->getContent()); + $this->assertContains('SwaggerLume', $response->response->getContent()); $this->assertContains('my-default-host.com', $response->response->getContent()); } /** @test */ public function canGenerateApiJsonFileWithChangedBasePath() { + if ($this->isOpenApi() == true) { + $this->markTestSkipped('only for openApi 2.0'); + } + $this->setPaths(); $cfg = config('swagger-lume'); @@ -40,7 +44,7 @@ public function canGenerateApiJsonFileWithChangedBasePath() $this->assertResponseOk(); - $this->assertContains('Swagger Lume API', $response->response->getContent()); + $this->assertContains('SwaggerLume', $response->response->getContent()); $this->assertContains('new_path', $response->response->getContent()); } @@ -77,32 +81,4 @@ public function canSetValidatorUrl() $this->assertTrue(file_exists($this->jsonDocsFile())); } - - /** @test */ - public function canGenerateApiJsonFileWithSecurityDefinition() - { - $this->setPaths(); - - $cfg = config('swagger-lume'); - $security = [ - 'new_api_key_securitye' => [ - 'type' => 'apiKey', - 'name' => 'api_key_name', - 'in' => 'query', - ], - ]; - $cfg['security'] = $security; - config(['swagger-lume' => $cfg]); - - Generator::generateDocs(); - - $this->assertTrue(file_exists($this->jsonDocsFile())); - - $response = $this->get(config('swagger-lume.routes.docs')); - - $this->assertResponseOk(); - - $this->assertContains('new_api_key_securitye', $response->response->getContent()); - $this->seeJson($security); - } } diff --git a/tests/LumenTestCase.php b/tests/LumenTestCase.php index f21133d..fb4cac2 100644 --- a/tests/LumenTestCase.php +++ b/tests/LumenTestCase.php @@ -85,11 +85,23 @@ public function createApplication() return $app; } + /** + * @return bool + */ + protected function isOpenApi() + { + return version_compare(config('swagger-lume.swagger_version'), '3.0', '>='); + } + protected function setPaths() { $cfg = config('swagger-lume'); //Changing path - $cfg['paths']['annotations'] = storage_path('annotations'); + $cfg['paths']['annotations'] = storage_path('annotations/Swagger'); + + if ($this->isOpenApi()) { + $cfg['paths']['annotations'] = storage_path('annotations/OpenApi'); + } //For test we want to regenerate always $cfg['generate_always'] = true; diff --git a/tests/SecurityDefinitionsTest.php b/tests/SecurityDefinitionsTest.php new file mode 100644 index 0000000..5462658 --- /dev/null +++ b/tests/SecurityDefinitionsTest.php @@ -0,0 +1,76 @@ +isOpenApi()) { + $this->markTestSkipped('only for openApi 2.0'); + } + + $this->setPaths(); + + $cfg = config('swagger-lume'); + $security = [ + 'new_api_key_securitye' => [ + 'type' => 'apiKey', + 'name' => 'api_key_name', + 'in' => 'query', + ], + ]; + $cfg['security'] = $security; + config(['swagger-lume' => $cfg]); + + tap(new Generator)->generateDocs(); + + $this->assertTrue(file_exists($this->jsonDocsFile())); + + $response = $this->get(config('swagger-lume.routes.docs')); + + $this->assertResponseOk(); + + $this->assertContains('new_api_key_securitye', $response->response->getContent()); + $this->seeJson($security); + } + + /** @test */ + public function canGenerateApiJsonFileWithSecurityDefinitionOpenApi3() + { + if (! $this->isOpenApi()) { + $this->markTestSkipped('only for openApi 3.0'); + } + + $this->setPaths(); + + $cfg = config('swagger-lume'); + $security = [ + 'new_api_key_security' => [ + 'type' => 'apiKey', + 'name' => 'api_key_name', + 'in' => 'query', + ], + ]; + $cfg['security'] = $security; + $cfg['swagger_version'] = '3.0'; + config(['swagger-lume' => $cfg]); + + tap(new Generator)->generateDocs(); + + $this->assertTrue(file_exists($this->jsonDocsFile())); + + $response = $this->get(config('swagger-lume.routes.docs')); + + $this->assertResponseOk(); + + $content = $response->response->getContent(); + + $this->assertContains('new_api_key_security', $content); + $this->assertContains('oauth2', $content); + $this->seeJson($security); + } +} diff --git a/tests/storage/annotations/OpenApi/Anotations.php b/tests/storage/annotations/OpenApi/Anotations.php new file mode 100644 index 0000000..e43b39e --- /dev/null +++ b/tests/storage/annotations/OpenApi/Anotations.php @@ -0,0 +1,119 @@ +