Lumen 微服務生成 Swagger 文件

mylxsw發表於2019-01-02

Xnip2019-01-02_16-07-57

作為一名phper,在使用Lumen框架開發微服務的時候,API文件的書寫總是少不了的,比較流行的方式是使用swagger來寫API文件,但是與Java語言原生支援 annotation 不同,php只能單獨維護一份swagger文件,或者在註釋中新增annotations來實現類似的功能,但是註釋中書寫Swagger註解是非常痛苦的,沒有程式碼提示,沒有格式化。

本文將會告訴你如何藉助phpstorm中annotations外掛,在開發Lumen微服務專案時(Laravel專案和其它php專案方法類似)快速的在程式碼中使用註釋來建立swagger文件。

本文將會持續修正和更新,最新內容請參考我的 GITHUB 上的 程式猿成長計劃 專案,歡迎 Star,更多精彩內容請 follow me

框架配置

我們使用當前最新的 Lumen 5.7 來演示。演示程式碼放到了github,感興趣的可以參考一下

https://github.com/mylxsw/lumen-swagger-demo

安裝依賴

在Lumen專案中,首先需要使用 composer 安裝SwaggerLume專案依賴

composer require darkaonline/swagger-lume

-w568

專案配置

bootstrap/app.php檔案中,去掉下面配置的註釋(大約在26行),啟用Facades支援。

$app->withFacades();

啟用SwaggerLume 專案的配置檔案,在 Register Container Bindings部 分前面,新增

$app->configure('swagger-lume');

然後,在 Register Service Providers 部分,註冊 SwaggerLume 的ServiceProvider

$app->register(\SwaggerLume\ServiceProvider::class);

在專案的根目錄,執行命令 php artisan swagger-lume:publish 釋出swagger相關的配置

-w406

執行該命令後,主要體現以下幾處變更

-w617

  • config/ 目錄中,新增了專案的配置檔案 swagger-lume.php
  • resources/views/vendor 目錄中,生成了 swagger-lume/index.blade.php 檢視檔案,用於預覽生成的API文件

從配置檔案中我們可以獲取以下關鍵資訊

  • api.title 生成的API文件顯示標題
  • routes.api 用於訪問生成的API文件UI的路由地址預設為 /api/documentation
  • routes.docs 用於訪問生成的API文件原文,json格式,預設路由地址為 /docs
  • paths.docspaths.docs_json 組合生成 api-docs.json 檔案的地址,預設為 storage/api-docs/api-docs.json,執行php artisan swagger-lume:generate命令時,將會生成該檔案

語法自動提示

純手寫swagger註釋肯定是要不得的,太容易出錯,還需要不停的去翻看文件參考語法,因此我們很有必要安裝一款能夠自動提示註釋中的註解語法的外掛,我們常用的IDE是 phpstorm,在 phpstorm 中,需要安裝 PHP annotation 外掛

安裝外掛之後,我們在寫Swagger文件時,就有程式碼自動提示功能了

2019-01-02 13_33_59

書寫文件

Swagger文件中包含了很多與具體API無關的資訊,我們在 app/Http/Controllers 中建立一個 SwaggerController,該控制器中我們不實現業務邏輯,只用來放置通用的文件資訊

<?php
namespace App\Http\Controllers;

use OpenApi\Annotations\Contact;
use OpenApi\Annotations\Info;
use OpenApi\Annotations\Property;
use OpenApi\Annotations\Schema;
use OpenApi\Annotations\Server;

/**
 *
 * @Info(
 *     version="1.0.0",
 *     title="演示服務",
 *     description="這是演示服務,該文件提供了演示swagger api的功能",
 *     @Contact(
 *         email="mylxsw@aicode.cc",
 *         name="mylxsw"
 *     )
 * )
 *
 * @Server(
 *     url="http://localhost",
 *     description="開發環境",
 * )
 *
 * @Schema(
 *     schema="ApiResponse",
 *     type="object",
 *     description="響應實體,響應結果統一使用該結構",
 *     title="響應實體",
 *     @Property(
 *         property="code",
 *         type="string",
 *         description="響應程式碼"
 *     ),
 *     @Property(property="message", type="string", description="響應結果提示")
 * )
 *
 *
 * @package App\Http\Controllers
 */
class SwaggerController
{}

接下來,在業務邏輯控制器中,我們就可以寫API了

<?php
namespace App\Http\Controllers;

use App\Http\Responses\DemoAdditionalProperty;
use App\Http\Responses\DemoResp;
use Illuminate\Http\Request;
use OpenApi\Annotations\Get;
use OpenApi\Annotations\MediaType;
use OpenApi\Annotations\Property;
use OpenApi\Annotations\RequestBody;
use OpenApi\Annotations\Response;
use OpenApi\Annotations\Schema;

class ExampleController extends Controller
{

    /**
     * @Get(
     *     path="/demo",
     *     tags={"演示"},
     *     summary="演示API",
     *     @RequestBody(
     *         @MediaType(
     *             mediaType="application/json",
     *             @Schema(
     *                 required={"name", "age"},
     *                 @Property(property="name", type="string", description="姓名"),
     *                 @Property(property="age", type="integer", description="年齡"),
     *                 @Property(property="gender", type="string", description="性別")
     *             )
     *         )
     *     ),
     *     @Response(
     *         response="200",
     *         description="正常操作響應",
     *         @MediaType(
     *             mediaType="application/json",
     *             @Schema(
     *                 allOf={
     *                     @Schema(ref="#/components/schemas/ApiResponse"),
     *                     @Schema(
     *                         type="object",
     *                         @Property(property="data", ref="#/components/schemas/DemoResp")
     *                     )
     *                 }
     *             )
     *         )
     *     )
     * )
     *
     * @param Request $request
     *
     * @return DemoResp
     */
    public function example(Request $request)
    {
        // TODO 業務邏輯

        $resp         = new DemoResp();
        $resp->name   = $request->input('name');
        $resp->id     = 123;
        $resp->age    = $request->input('age');
        $resp->gender = $request->input('gender');

        $prop1        = new DemoAdditionalProperty();
        $prop1->key   = "foo";
        $prop1->value = "bar";

        $prop2        = new DemoAdditionalProperty();
        $prop2->key   = "foo2";
        $prop2->value = "bar2";

        $resp->properties = [$prop1, $prop2];

        return $resp;
    }
}

這裡,我們在響應結果中,引用了在SwaggerController中定義的 ApiResponse,還引用了一個沒有定義的ExampleResp物件,我們可以 app\Http\Responses 目錄(自己建立該目錄)中實現該ExampleResp物件,我們將響應物件都放在這個目錄中

<?php

namespace App\Http\Responses;

use OpenApi\Annotations\Items;
use OpenApi\Annotations\Property;
use OpenApi\Annotations\Schema;

/**
 * @Schema(
 *     title="demo響應內容",
 *     description="demo響應內容描述"
 * )
 *
 * @package App\Http\Responses
 */
class DemoResp extends JsonResponse
{

    /**
     * @Property(
     *     type="integer",
     *     description="ID"
     * )
     *
     * @var int
     */
    public $id = 0;

    /**
     * @Property(
     *     type="string",
     *     description="使用者名稱"
     * )
     *
     * @var string
     */
    public $name;

    /**
     * @Property(
     *     type="integer",
     *     description="年齡"
     * )
     *
     * @var integer
     */
    public $age;

    /**
     * @Property(
     *     type="string",
     *     description="性別"
     * )
     *
     * @var string
     */
    public $gender;

    /**
     * @Property(
     *     type="array",
     *     @Items(ref="#/components/schemas/DemoAdditionalProperty")
     * )
     *
     * @var array
     */
    public $properties = [];
}

返回物件引用其它物件

<?php
namespace App\Http\Responses;

use OpenApi\Annotations\Property;
use OpenApi\Annotations\Schema;

/**
 *
 * @Schema(
 *     title="額外屬性",
 *     description="額外屬性描述"
 * )
 *
 * @package App\Http\Responses
 */
class DemoAdditionalProperty
{
    /**
     * @Property(
     *     type="string",
     *     description="KEY"
     * )
     *
     * @var string
     */
    public $key;

    /**
     * @Property(
     *     type="string",
     *     description="VALUE"
     * )
     *
     * @var string
     */
    public $value;
}

生成文件

執行下面的命令,就可以生成文件了,生成的文件在storage/api-docs/api-docs.json

php artisan swagger-lume:generate

預覽文件

開啟瀏覽器訪問 http://訪問地址/docs,可以看到如下內容

訪問 http://訪問地址/api/documentation,我們看到

介面詳細資訊展開

更多

本文簡述瞭如何在Lumen專案中使用程式碼註釋自動生成Swagger文件,並配合phpstorm的程式碼提示功能,然而,學會了這些還遠遠不夠,你還需要去了解Swagger文件的語法結構,在 swagger-php 專案的 Examples 目錄中包含很多使用範例,你可以參考一下。

團隊專案中使用了swagger文件,但是總得有個地方管理文件吧,這裡推薦一下 Wizard 專案,該專案是一款用於團隊協作的文件管理工具,支援Markdown文件和Swagger文件,感興趣的不妨嘗試一下。

相關文章