從零寫一個自動生成API文件的laravel擴充套件包

hanyunmuyu發表於2020-10-11

手把手教你從零開始寫一個laravel擴充套件包,併發布到packagist,為世界的開源世界做出你自己的貢獻

  • 建立一個laravel專案
  • 在專案的根目錄建立一個目錄packages用於儲存測試的擴充套件包,目錄結果如下
packages
├── hanyun
│ └── swagger
│     └── src
  • 建立Commands目錄用於生成console命令
  • 建立Controllers目錄用於儲存控制器
  • 建立config目錄用於儲存配置檔案
  • 建立routes目錄 用於存放我們的路由
  • 建立swagger-ui目錄用於存放swagger的靜態頁面
  • 建立view目錄用於存放顯示UI的介面

引入swagger-ui

從swagger官網下載依賴檔案,將disk下的檔案複製到 packages/hanyun/swagger/src/swagger-ui/dist下面

│         ├── swagger-ui
│         │ └── dist
│         │     ├── favicon-16x16.png
│         │     ├── favicon-32x32.png
│         │     ├── index.html
│         │     ├── oauth2-redirect.html
│         │     ├── swagger-ui-bundle.js
│         │     ├── swagger-ui-bundle.js.map
│         │     ├── swagger-ui-es-bundle-core.js
│         │     ├── swagger-ui-es-bundle-core.js.map
│         │     ├── swagger-ui-es-bundle.js
│         │     ├── swagger-ui-es-bundle.js.map
│         │     ├── swagger-ui-standalone-preset.js
│         │     ├── swagger-ui-standalone-preset.js.map
│         │     ├── swagger-ui.css
│         │     ├── swagger-ui.css.map
│         │     ├── swagger-ui.js
│         │     └── swagger-ui.js.map

建立swagger的配置檔案,

檔案位置 /packages/hanyun/swagger/src/config/swagger.php


<?php
/**
 * User=> Only
 * Time=> 16=>30
 */
return [
    "info" => [
        "title" => "laravel swagger",
        "description" => 'laravel swagger generate OpenApi',
        "termsOfService" => "http://swagger.io/terms/",
        "contact" => [
            "email" => "1355081829@qq.com"
        ],
        "license" => [
            "name" => "MIT",
            "url" => ""
        ],
        "version" => "1.0.0"
    ],
    "servers" => [
        [
            "url" => "/",
            "description" => "laravel swagger OpenApi host"
        ]
    ],
];

建立檢視

檔案位置 packages/hanyun/swagger/src/view/index.blade.php後面會把這個檔案釋出到laravel的view目錄下面

<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Swagger UI</title>
    <link rel="stylesheet" type="text/css" href="{{asset('swagger-ui/swagger-ui.css')}}" >
    <link rel="icon" type="image/png" href="{{asset('swagger-ui/favicon-32x32.png')}}" sizes="32x32" />
    <link rel="icon" type="image/png" href="{{asset('swagger-ui/favicon-16x16.png')}}" sizes="16x16" />
    <style>
      html
      {
        box-sizing: border-box;
        overflow: -moz-scrollbars-vertical;
        overflow-y: scroll;
      }

      *,
      *:before,
      *:after
      {
        box-sizing: inherit;
      }

      body
      {
        margin:0;
        background: #fafafa;
      }
    </style>
  </head>

  <body>
    <div id="swagger-ui"></div>

    <script src="{{asset('swagger-ui/swagger-ui-bundle.js')}}" charset="UTF-8"> </script>
    <script src="{{asset('swagger-ui/swagger-ui-standalone-preset.js')}}" charset="UTF-8"> </script>
    <script>
    window.onload = function() {
      // Begin Swagger UI call region
      const ui = SwaggerUIBundle({
        url: "{{asset('swagger-ui/swagger.json')}}",
        dom_id: '#swagger-ui',
        deepLinking: true,
        presets: [
          SwaggerUIBundle.presets.apis,
          SwaggerUIStandalonePreset
        ],
        plugins: [
          SwaggerUIBundle.plugins.DownloadUrl
        ],
        layout: "StandaloneLayout"
      })
      // End Swagger UI call region

      window.ui = ui
    }
  </script>
  </body>
</html>

建立控制器,用於顯示文件介面

檔案位置 packages/hanyun/swagger/src/Controllers/SwaggerController.php


<?php

namespace Hanyun\Swagger\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class SwaggerController extends Controller
{

    //
    public function index()
    {
        return view('swagger-ui.index');
    }
}


建立路由

檔案位置 packages/hanyun/swagger/src/routes/swagger.php


<?php
/**
 * User: Only
 * Time: 17:04
 */

use Illuminate\Support\Facades\Route;

Route::get('/swagger', [\Hanyun\Swagger\Controllers\SwaggerController::class, 'index']);

建立console命令用於生成文件

檔案位置 packages/hanyun/swagger/src/Commands/Swagger.php


<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class Swagger extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'swagger:generate';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Generate swagger API';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {

        $openapi = \OpenApi\scan(app_path() . '/Http/Controllers');
        header('Content-Type: application/json');
        $json = $openapi->toJson();
        $json = preg_replace('/\s{0,}\*\s{0,}#\s{0,}/', '# ', $json);
        $json = preg_replace('/\s{0,}\\\\r\\\\n\s{0,}/', '\n', $json);
        $json = preg_replace('/\s{0,}\*\s{0,}/', '', $json);
        $arr = json_decode($json, true);
        $arr['info'] = config('swagger.info');
        $arr['servers'] = config('swagger.servers');
        $json = json_encode($arr);
        file_put_contents(public_path('swagger-ui/swagger.json'), $json);
        return 0;
    }
}


建立門面

檔案位置 packages/hanyun/swagger/src/Facades/Swagger.php


<?php
/**
 * User: Only
 * Time: 16:39
 */

namespace Hanyun\Swagger\Facades;

use Illuminate\Support\Facades\Facade;

class Swagger extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'swagger';
    }
}

建立provider用於釋出擴充套件

檔案位置 packages/hanyun/swagger/src/SwaggerProvider.php


<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class Swagger extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'swagger:generate';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Generate swagger API';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {

        $openapi = \OpenApi\scan(app_path() . '/Http/Controllers');
        header('Content-Type: application/json');
        $json = $openapi->toJson();
        $json = preg_replace('/\s{0,}\*\s{0,}#\s{0,}/', '# ', $json);
        $json = preg_replace('/\s{0,}\\\\r\\\\n\s{0,}/', '\n', $json);
        $json = preg_replace('/\s{0,}\*\s{0,}/', '', $json);
        $arr = json_decode($json, true);
        $arr['info'] = config('swagger.info');
        $arr['servers'] = config('swagger.servers');
        $json = json_encode($arr);
        file_put_contents(public_path('swagger-ui/swagger.json'), $json);
        return 0;
    }
}

修改我們建立的擴充套件包下面的 composer.json


{
    "name": "hanyun/swagger",
    "description": "Swagger for laravel",
    "keywords": [
        "swagger",
        "laravel",
        "openapi"
    ],
    "license": "MIT",
    "authors": [
        {
            "name": "hanyun",
            "email": "1355081829@qq.com"
        }
    ],
    "autoload": {
        "psr-4": {
            "Hanyun\\Swagger\\": "src/"
        }
    },
    "require": {
        "php": "^7.3",
        "zircote/swagger-php": "^3.1"
    }
}

修改我們建立的laravel專案下的composer.json

"Hanyun\\Swagger\\": "packages/hanyun/swagger/src" 讓我們的專案可以引入我們的擴充套件包做測試,測試透過之後我們可以把我們的擴充套件包釋出到GitHub上面,然後再發布到https://packagist.org,這樣其他人就可以透過composer引入你的擴充套件包

    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Hanyun\\Swagger\\": "packages/hanyun/swagger/src",
            "Database\\Factories\\": "database/factories/",
            "Database\\Seeders\\": "database/seeders/"
        }
    }

最終目錄結果如下:

packages
├── hanyun
│ └── swagger
│     └── src
│         ├── Commands
│         │ └── Swagger.php
│         ├── Controllers
│         │ └── SwaggerController.php
│         ├── Facades
│         │ └── Swagger.php
│         ├── Swagger.php
│         ├── SwaggerProvider.php
│         ├── config
│         │ └── swagger.php
│         ├── routes
│         │ └── swagger.php
│         ├── swagger-ui
│         │ └── dist
│         │     ├── favicon-16x16.png
│         │     ├── favicon-32x32.png
│         │     ├── index.html
│         │     ├── oauth2-redirect.html
│         │     ├── swagger-ui-bundle.js
│         │     ├── swagger-ui-bundle.js.map
│         │     ├── swagger-ui-es-bundle-core.js
│         │     ├── swagger-ui-es-bundle-core.js.map
│         │     ├── swagger-ui-es-bundle.js
│         │     ├── swagger-ui-es-bundle.js.map
│         │     ├── swagger-ui-standalone-preset.js
│         │     ├── swagger-ui-standalone-preset.js.map
│         │     ├── swagger-ui.css
│         │     ├── swagger-ui.css.map
│         │     ├── swagger-ui.js
│         │     └── swagger-ui.js.map
│         └── view
│             └── index.blade.php


測試

1、專案的/config/app.php 的providers陣列裡面新增 \Hanyun\Swagger\SwaggerProvider::class
如下所示

```
    'providers' => [
        //...其他的依賴
        \Hanyun\Swagger\SwaggerProvider::class
    ],

```

2、專案的/config/app.php 的aliases陣列裡面新增 'swagger'=>\Hanyun\Swagger\Facades\Swagger::class
如下所示

    'aliases' => [
        //...   其他的省略
        'swagger'=>\Hanyun\Swagger\Facades\Swagger::class
    ],

3、在專案根目錄執行 php artisan vendor:publish , 找到 [4 ] Provider: Hanyun\Swagger\SwaggerProvider 這一行,輸入前面的數字,按回車

4、執行 php artian make:controller Api/v1/IndexController 生成控制器,修改程式碼


<?php

namespace App\Http\Controllers\Api\v1;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use OpenApi\Annotations as OA;

class IndexController extends Controller
{
    //
    /**
     * @OA\Get(
     *     path="/api/index",
     *   security={{
     *     "api_key":{}
     *   }},
     *     @OA\Response(response="200", description="
     *      |引數|說明|備註||||
     *      |:---:|:---:|:---:|-----|-----|-----|
     *      |status|狀態|['已取消', '等待付款', '下單成功', '付款中'] 取陣列索引||||
     *     ")
     * )
     */
    public function index(Request $request)
    {
        return $request->all();
    }
}

修改 App\Http\Controllers\Controller.php 程式碼如下


<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
use OpenApi\Annotations as OA;


/**
 * @OA\OpenApi(
 *     @OA\Info(
 *         version="1.0.0",
 *         title="Swagger Petstore",
 *         description="This is a sample server Petstore server.  You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).  For this sample, you can use the api key `special-key` to test the authorization filters.",
 *         termsOfService="http://swagger.io/terms/",
 *         @OA\Contact(
 *             email="apiteam@swagger.io"
 *         ),
 *         @OA\License(
 *             name="Apache 2.0",
 *             url="http://www.apache.org/licenses/LICENSE-2.0.html"
 *         )
 *     ),
 *     @OA\Server(
 *         description="OpenApi host",
 *         url="https://petstore.swagger.io/v3"
 *     ),
 *     @OA\ExternalDocumentation(
 *         description="Find out more about Swagger",
 *         url="http://swagger.io"
 *     )
 * )
 * @OA\SecurityScheme(
 *   securityScheme="api_key",
 *   type="apiKey",
 *   in="header",
 *   name="Authorization"
 * )
 */
class Controller extends BaseController
{
    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

5、修改 config/swagger.php 這個會自動覆蓋swagger的預設配置資訊

6、在專案根目錄執行 php artisan swagger:generate,生成API

7、專案根目錄執行 php artisan serve,開啟 專案文件

釋出我們的擴充套件包

1、提交到GitHub上面

2、釋出到ackagist.org

開啟ackagist.org
輸入你的擴充套件包的GitHub地址,點選check,就生成了擴充套件包

具體的swagger文件zircote/swagger-php文件

github地址 歡迎大家star和fork

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章