在PHP中寫複雜的Swagger定義時如何偷懶(基於zircote/swagger-php)
Swagger大大降低了介面提供者和接入者之間的溝通和維護成本,如果你還不瞭解Swagger的話,可以看我的另一篇文章《Laravel(PHP)使用Swagger生成API文件不完全指南 - 基本概念和環境搭建》
在PHP中使用Swagger,大多都會用到zircote/swagger-php
這個Composer庫。以Laravel
專案為例,我們通常會為每個Controller的返回寫一個單獨的Swagger Definition
以方便管理,然後在Controller的Annotation
中寫下這樣的規則:
<?php
// ...
/**
* 假設是專案中的一個API
*
* @SWG\Get(path="/swagger/my-data",
* tags={"project"},
* summary="拿一些神祕的資料",
* description="請求該介面需要先登入。",
* operationId="getMyData",
* produces={"application/json"},
* @SWG\Parameter(
* in="formData",
* name="reason",
* type="string",
* description="拿資料的理由",
* required=true,
* ),
* @Swagger\Annotations\Schema(ref="#/definitions/MyDataResponse"),
* )
*/
public function getMyData()
{
//todo 待實現
}
// ...
而上面引用的MyDataResponse
的定義看起來可能是這樣:
<?php
/**
* @SWG\Definition
*/
class MyDataResponse
{
/**
* @var string
* @SWG\Property(example="Alan Jones")
*/
public $data;
}
注意,$data
欄位定義中設定了example
屬性,這實際上是給$data
欄位舉了一個返回值的例子,這樣不光可以把Swagger
定義匯入工具中做介面Mock
(example即是Mock
介面的返回值)、在Swagger UI
返回格式同樣也一目瞭然:
但有時這些簡單的整型或者字串example就無法滿足專案需求了,例如你可能會需要返回這樣一個資料結構:
{
"data": {
"current_level": 1,
"machine_detail": {
"sn": "77777777",
"mode": "extreme"
}
"records": [
{
"time": "2017-03-28 00:00:00",
"message": "machine started"
}
]
}
}
正常來講,我們應該針對例子中的data
、machine_detail
和record
(records
中的每一個元素)分別建立Definition
,然後在定義中去寫引用(ref=
)。但有時我們就是突然感覺很懶啊!又或者這些資料結構只有這一個介面使用,實在不值當單獨定義幾個Definition
去實現啊(還是懶)!
那麼怎麼辦呢?我簡單總結了三個方法。
1. 直接把複雜結構寫在example
中
如下:
<?php
//...
/**
* @SWG\Property(
* example={"current_level": 1, [省略] "records": { { "time" [繼續省略] } } },
* )
* @var object
*/
public $data;
//...
這種做法最大的壞處就是在註釋中排版實在很痛苦……另外要注意得把JSON的陣列括號(方括號)寫成花括號(這是zircote/swagger-php
的限制)。
2. 使用JSON檔案定義
我們可以單獨把這一個$data
的Definition
寫在一個JSON檔案中,如data.json
,然後在註釋(Annotation)中寫一個引用:
<?php
//...
/**
* @SWG\Property(
* ref="data.json",
* )
*/
public $data;
//...
data.json
內容為:
{
"current_level": 1,
"machine_detail": {
"sn": "77777777",
"mode": "extreme"
}
"records": [
{
"time": "2017-03-28 00:00:00",
"message": "machine started"
}
]
}
這樣Swagger UI
在載入完之後還會去請求data.json
來獲取定義內容,最終效果是一樣的。但壞處是一部分Definition
被拆到了另一個檔案,一個JSON搞不定,而且請求多了也會慢。
3. 靈活使用zircote/swagger-php
讓我們先回頭看看是怎麼使用zircote/swagger-php
返回JSON格式Swagger
定義的:
<?php
// ...
/**
* @SWG\Swagger(
* @SWG\Info(
* title="我的`Swagger`API文件",
* version="1.0.0"
* )
* )
*/
public function getJSON()
{
$swagger = \Swagger\scan(app_path('Http/Controllers/'));
return response()->json($swagger, 200); //注意這一句我們直接把$swagger傳給了json()方法
}
// ...
注意示例中的$swagger
物件。
在呼叫\Swagger\scan()
方法時,實際上是掃描你指定的所有目錄和檔案,將其中符合規則的Swagger Annotation
解析出來,並轉換為各種Class(在Swagger\Annotations
名字空間下可以找到),最終這些Annotation
物件都會被載入到$swagger
物件裡(Swagger\Annotations\Swagger)。$swagger
是一個JsonSerializable
,所以可以直接作為json_encode()
函式的引數,在轉換過程中,內部的各種定義物件就會被處理成一個可以JSON化的stdClass
。
那麼我們其實可以把最終生成的資料拿到,然後把複雜的定義直接寫成PHP陣列,在最後和$swagger
轉換結果中的definitions
進行合併就可以了。之前也試過直接手動新建Swagger\Annotations\Definition
物件,然後合併到$swagger->definitions
陣列中,但發現這寫起來遠沒有直接寫陣列的效率高。
在專案中我將這些手寫的Definition
分檔案存放,然後寫了一個方法載入,最後合併到返回中。
上面例子的檔案內容可以寫成這樣:
<?php
return [
"current_level" => 1,
"machine_detail" => [
"sn" => "77777777",
"mode" => "extreme"
]
"records" => [
[
"time" => "2017-03-28 00 =>00 =>00",
"message" => "machine started"
]
]
];
以及改過之後的getJSON()
方法:
<?php
// ...
/**
* @SWG\Swagger(
* @SWG\Info(
* title="我的`Swagger`API文件",
* version="1.0.0"
* )
* )
*/
public function getJSON()
{
$swagger = \Swagger\scan(app_path('Http/Controllers/'));
return response()->json(
mergeWithRawDefinitions($swagger, loadRawDefinition(app_path('Swagger/Raw/'))),
200
);
}
// ...
本文僅僅是拋磚引玉,如果你有更“懶”的方法,歡迎在評論中與大家分享!
相關文章
- 偷懶寫指令碼中特殊符號的轉譯指令碼符號
- 程式設計師如何偷懶?偷懶是一種至高境界程式設計師
- Laravel 8 開發中使用 swagger-php 3 生成文件LaravelSwaggerPHP
- 有哪些excel的好習慣,能幫你在工作時偷懶?Excel
- PHP 演算法基礎----時間複雜度和空間複雜度(轉載)PHP演算法時間複雜度
- 如何正確的(?)利用 Vue.mixin() 偷懶Vue
- 模型的列表定義中,使用函式時如何定義引數?模型函式
- php中定義類PHP
- 時間複雜度怎麼算?如何計算時間複雜度?時間複雜度
- 如何通過 JavaCSV 類庫來優雅地(偷懶)讀寫 CSV 檔案?Java
- “偷懶”不等於換皮 案例解析遊戲廠商如何又省又賺遊戲
- 關於計算時間複雜度和空間複雜度時間複雜度
- 複雜系統的有界上下文和聚合結構是如何定義的?
- 你的程式設計師是在努力工作還是在偷懶?程式設計師
- 在Excel中巧做複雜表頭Excel
- [譯]在 Flutter 中解析複雜的 JSONFlutterJSON
- iOS 開發偷懶小技巧:自定義 XCode 程式碼片段iOSXCode
- PHP陣列函式的時間複雜度清單PHP陣列函式時間複雜度
- 如何查詢方法在jQuery庫中定義的位置jQuery
- 關於轉義符 在php正則中的匹配問題PHP
- 【基礎】演算法的時間複雜度分析演算法時間複雜度
- 【原】關於資料倉儲中複雜報表SQL語句的寫法SQL
- Linux 如何設定密碼複雜度?Linux密碼複雜度
- 偷懶祕訣之變數篇變數
- 記一次偷懶實踐
- 在Java中是如何定義和宣告介面的?Java
- 在Qml 中定義訊號並如何觸發
- 時間複雜度跟空間複雜度時間複雜度
- 時間複雜度和空間複雜度時間複雜度
- 時間複雜度與空間複雜度時間複雜度
- oracle中關於null的定義OracleNull
- 基於tcp的應用層訊息邊界如何定義TCP
- android中自定義屬性重複定義Android
- PHP核心探索:寫時複製COW機制PHP
- 懶得寫文件,swagger文件匯出來不香嗎Swagger
- php變數的型別是如何轉換的?常量如何定義?系統常量是如何定義的?PHP變數型別
- PHP 陣列排序(複雜字串)PHP陣列排序字串
- 關於定時任務的一些雜談