Skip to content

Commit

Permalink
Merge pull request #21 from nextapps-be/feature/add_multiple_file_and…
Browse files Browse the repository at this point in the history
…_version_support
  • Loading branch information
yinx authored Mar 30, 2023
2 parents 0dd2ca3 + b580322 commit 795422b
Show file tree
Hide file tree
Showing 13 changed files with 226 additions and 155 deletions.
18 changes: 2 additions & 16 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,13 @@ jobs:
strategy:
fail-fast: false
matrix:
php: [7.4, 8.0, 8.1, 8.2]
laravel: [8.*, 9.*, 10.*]
php: [8.1, 8.2]
laravel: [9.*, 10.*]
dependency-version: [prefer-lowest, prefer-stable]
exclude:
- php: 8.2
laravel: 9.*
dependency-version: prefer-lowest
- php: 8.2
laravel: 8.*
- php: 8.1
laravel: 8.*
dependency-version: prefer-lowest
- php: 8.0
laravel: 10.*
- php: 8.0
laravel: 8.*
dependency-version: prefer-lowest
- php: 7.4
laravel: 9.*
- php: 7.4
laravel: 10.*

name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - ${{ matrix.dependency-version }}

Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ protected function gate()
```

In the published `config/swagger-ui.php` file, you edit the path to the Swagger UI and the location of the Swagger (OpenAPI v3) file. By default, the package expects to find the OpenAPI file in 'resources/swagger' directory. You can also provide an url if the OpenAPI file is not present in the Laravel project itself.
This is also where you can define multiple versions for the same api.

```php
// in config/swagger-ui.php
Expand All @@ -53,7 +54,9 @@ return [

'path' => 'swagger',

'file' => resource_path('swagger/openapi.json'),
'versions' => [
'v1' => resource_path('swagger/openapi.json')
],

// ...
];
Expand Down
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@
}
],
"require": {
"php": "^7.4|^8.0|^8.1|^8.2",
"php": "^8.1|^8.2",
"ext-json": "*",
"laravel/framework": "^8.0|^9.0|^10.0"
"laravel/framework": "^9.0|^10.0"
},
"suggest": {
"ext-yaml": "*"
},
"require-dev": {
"adamwojs/php-cs-fixer-phpdoc-force-fqcn": "^2.0",
"friendsofphp/php-cs-fixer": "^3.0",
"jasonmccreary/laravel-test-assertions": "^2.3",
"orchestra/testbench": "^6.0|^7.0|^8.0",
"phpunit/phpunit": "^9.1",
"squizlabs/php_codesniffer": "^3.6"
Expand Down
112 changes: 44 additions & 68 deletions config/swagger-ui.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,73 +3,49 @@
use NextApps\SwaggerUi\Http\Middleware\EnsureUserIsAuthorized;

return [
/*
|--------------------------------------------------------------------------
| Swagger UI - Path
|--------------------------------------------------------------------------
|
| This is the URI path where SwaggerUI will be accessible from. Feel free
| to change this path to anything you like.
|
*/

'path' => 'swagger',

/*
|--------------------------------------------------------------------------
| Swagger UI - Route Middleware
|--------------------------------------------------------------------------
|
| These middleware will be assigned to every Swagger UI route.
|
*/

'middleware' => [
'web',
EnsureUserIsAuthorized::class,
],

/*
|--------------------------------------------------------------------------
| Swagger UI - OpenAPI File
|--------------------------------------------------------------------------
|
| This is the location of the project's OpenAPI / Swagger JSON file. It's
| this file that will be used in Swagger UI. This can either be a local
| file or an url to a file.
|
*/

'file' => resource_path('swagger/openapi.json'),

/*
|--------------------------------------------------------------------------
| Swagger UI - Modify File
|--------------------------------------------------------------------------
|
| If this option is enabled, then the file will be changed before it is
| used by Swagger UI. The server url and oauth urls will be changed to
| the base url of this Laravel application.
|
*/

'modify_file' => true,

/*
|--------------------------------------------------------------------------
| Swagger UI - OAuth Config
|--------------------------------------------------------------------------
|
| This allows you to configure oauth within Swagger UI. It makes it easier
| to authenticate in Swagger UI by prefilling certain values.
|
*/
'oauth' => [
'token_path' => 'oauth/token',
'refresh_path' => 'oauth/token',
'authorization_path' => 'oauth/authorize',

'client_id' => env('SWAGGER_UI_OAUTH_CLIENT_ID'),
'client_secret' => env('SWAGGER_UI_OAUTH_CLIENT_SECRET'),
'files' => [
[
/*
* The path where the swagger file is served.
*/
'path' => 'swagger',

/*
* The versions of the swagger file. The key is the version name and the value is the path to the file.
*/
'versions' => [
'v1' => resource_path('swagger/openapi.json'),
],

/*
* The default version that is loaded when the route is accessed.
*/
'default' => 'v1',

/*
* The middleware that is applied to the route.
*/
'middleware' => [
'web',
EnsureUserIsAuthorized::class,
],

/*
* If enabled the file will be modified to set the server url and oauth urls.
*/
'modify_file' => true,

/*
* The oauth configuration for the swagger file.
*/
'oauth' => [
'token_path' => 'oauth/token',
'refresh_path' => 'oauth/token',
'authorization_path' => 'oauth/authorize',

'client_id' => env('SWAGGER_UI_OAUTH_CLIENT_ID'),
'client_secret' => env('SWAGGER_UI_OAUTH_CLIENT_SECRET'),
],
],
],
];
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 14 additions & 4 deletions resources/views/index.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,32 @@
<div id="swagger-ui"></div>

<script src="https://unpkg.com/swagger-ui-dist@latest/swagger-ui-bundle.js"></script>
<script src="https://unpkg.com/swagger-ui-dist@latest/swagger-ui-standalone-preset.js"></script>

<script>
window.onload = function () {
window.ui = SwaggerUIBundle({
url: '{{ route('swagger-openapi-json', [], false) }}',
urls: [
@foreach ($data['versions'] as $version => $path)
{
url: '{{ ltrim($data['path'], '/') . '/' . $version }}',
name: '{{ $version }}',
},
@endforeach
],
"urls.primaryName": "{{$data['default']}}",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
layout: 'BaseLayout',
layout: 'StandaloneLayout',
});
ui.initOAuth({
clientId: '{{ config('swagger-ui.oauth.client_id') }}',
clientSecret: '{{ config('swagger-ui.oauth.client_secret') }}',
clientId: '{{ $data['oauth']['client_id'] }}',
clientSecret: '{{ $data['oauth']['client_secret'] }}',
});
};
</script>
Expand Down
48 changes: 32 additions & 16 deletions src/Http/Controllers/OpenApiJsonController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,42 @@

namespace NextApps\SwaggerUi\Http\Controllers;

use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\ItemNotFoundException;
use Illuminate\Support\Str;
use RuntimeException;

class OpenApiJsonController
{
public function __invoke() : JsonResponse
public function __invoke(Request $request, string $filename) : JsonResponse
{
$json = $this->getJson();
$path = $request->segment(1);

try {
$file = collect(config('swagger-ui.files'))->filter(function ($values) use ($filename, $path) {
return isset($values['versions'][$filename]) && ltrim($values['path'], '/') === $path;
})->firstOrFail();
} catch (ItemNotFoundException) {
return abort(404);
}

$json = $this->getJson($file['versions'][$filename]);

$json = $this->configureServer($json);
$json = $this->configureOAuth($json);
$json = $this->configureServer($file, $json);
$json = $this->configureOAuth($file, $json);

return response()->json($json);
}

protected function getJson() : array
protected function getJson(string $path) : array
{
$path = config('swagger-ui.file');
$content = file_get_contents($path);
try {
$content = file_get_contents($path);
} catch (Exception $e) {
throw new RuntimeException('OpenAPI file can not be read');
}

if (Str::endsWith($path, '.yaml')) {
if (! extension_loaded('yaml')) {
Expand All @@ -34,9 +50,9 @@ protected function getJson() : array
return json_decode($content, true);
}

protected function configureServer(array $json) : array
protected function configureServer(array $file, array $json) : array
{
if (! config('swagger-ui.modify_file')) {
if (! $file['modify_file']) {
return $json;
}

Expand All @@ -47,28 +63,28 @@ protected function configureServer(array $json) : array
return $json;
}

protected function configureOAuth(array $json) : array
protected function configureOAuth(array $file, array $json) : array
{
if (empty($json['components']['securitySchemes']) || ! config('swagger-ui.modify_file')) {
if (empty($json['components']['securitySchemes']) || ! $file['modify_file']) {
return $json;
}

$securitySchemes = collect($json['components']['securitySchemes'])->map(function ($scheme) {
$securitySchemes = collect($json['components']['securitySchemes'])->map(function ($scheme) use ($file) {
if ($scheme['type'] !== 'oauth2') {
return $scheme;
}

$scheme['flows'] = collect($scheme['flows'])->map(function ($flow) {
$scheme['flows'] = collect($scheme['flows'])->map(function ($flow) use ($file) {
if (isset($flow['tokenUrl'])) {
$flow['tokenUrl'] = url(config('swagger-ui.oauth.token_path'));
$flow['tokenUrl'] = url($file['oauth']['token_path']);
}

if (isset($flow['refreshUrl'])) {
$flow['refreshUrl'] = url(config('swagger-ui.oauth.refresh_path'));
$flow['refreshUrl'] = url($file['oauth']['refresh_path']);
}

if (isset($flow['authorizationUrl'])) {
$flow['authorizationUrl'] = url(config('swagger-ui.oauth.authorization_path'));
$flow['authorizationUrl'] = url($file['oauth']['authorization_path']);
}

return $flow;
Expand Down
22 changes: 22 additions & 0 deletions src/Http/Controllers/SwaggerViewController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace NextApps\SwaggerUi\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\ItemNotFoundException;

class SwaggerViewController
{
public function __invoke(Request $request)
{
try {
$file = collect(config('swagger-ui.files'))->filter(function ($values) use ($request) {
return ltrim($values['path'], '/') === $request->path();
})->firstOrFail();
} catch (ItemNotFoundException) {
return abort(404);
}

return view('swagger-ui::index', ['data' => collect($file)]);
}
}
17 changes: 9 additions & 8 deletions src/SwaggerUiServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use Illuminate\Support\ServiceProvider;
use NextApps\SwaggerUi\Console\InstallCommand;
use NextApps\SwaggerUi\Http\Controllers\OpenApiJsonController;
use NextApps\SwaggerUi\Http\Middleware\EnsureUserIsAuthorized;
use NextApps\SwaggerUi\Http\Controllers\SwaggerViewController;

class SwaggerUiServiceProvider extends ServiceProvider
{
Expand Down Expand Up @@ -36,12 +36,13 @@ public function register() : void

protected function loadRoutes() : void
{
Route::middleware(config('swagger-ui.middleware', ['web', EnsureUserIsAuthorized::class]))
->prefix(config('swagger-ui.path'))
->group(function () {
Route::view('/', 'swagger-ui::index')->name('swagger-ui');

Route::get('openapi.json', OpenApiJsonController::class)->name('swagger-openapi-json');
});
collect(config('swagger-ui.files'))->each(function ($values) {
Route::middleware($values['middleware'])
->group(function () use ($values) {
Route::get($values['path'], SwaggerViewController::class)->name($values['path'] . '.index');

Route::get($values['path'] . '/{filename}', OpenApiJsonController::class)->name($values['path'] . '.json');
});
});
}
}
Loading

0 comments on commit 795422b

Please sign in to comment.