問題的一開始源於客戶和服務部門抱怨我的REST API文檔寫得不好,然后又了解到 django rest framework 利用 coreapi 能自動生成文檔,再就是看到 swagger.io 上說得天花亂墜的,OpenAPI文檔寫完后,可以生成40種語言的客戶端代碼(用戶都不用文檔了,代碼都生成了!!),外加N種服務端stub代碼,另外演示文檔真心漂亮。於是我開始了研究 REST API specification的各種語言了,這里簡單總結備忘下。
API specification
API sepecification有很多種語言,主流的有3種
- OpenAPI (swagger)
- RAML
- API blueprint
我最開始研究的是openapi,沒寫幾個endpoint我就放棄了,層次太深,縮進了幾層之后,完全不知道自己在什么地方了。
我馬上轉去研究 api blueprint,這個挺好,有專門的emacs apib-mode,而且層次沒有那么深,看起來更直白一點,甚至自己搞了 MSON 的規范,總之寫起來更像是給人看的,而不是給機器看的。apib的工具相對較少,好在可以轉成 openapi,然后再生成代碼等等 。不過,好景不長,稍微復雜一點的API表達能力就有限了(需要復制、粘貼),表達得也不是那么直白。
以我python程序員的角度看問題,這種東西應該由python來寫,每個可利用的模塊定義成function或class,然后引用一點,這樣也可以將api spec拆分成小塊,又要看,又好維護。事實上,確定有一個叫 openapi 的package,完成了這件事情,可以用它來寫,不過只支持 2.0,就沒有仔細研究了。
我沒有再去研究RAML,因為它也是yaml,所以層次問題肯定也存在,我去試也下基於Eclipse的KaiZen編輯器,層次問題仍然存在,雖然有outline、補全提示和template,但層次問題仍然不好解決。據說 jetbrains 平台也有類似的插件,我沒有去試。
正當我鬧心的時候,我搜索到了這么一篇文章,說的是使用json ref來把swagger文檔拆分成多個,雖然文章結尾給出的方法 json-refs resolve無法達到他說的那樣,但是思想是好的,於是我自己花一天時間寫了一個工具,實現了文章上說的方法,並且不會展開local ref,在openapi最后文檔中仍然保留對schema的ref。
Swagger-tools
openapi號稱有很多工具,並且官方網站上也一直在宣傳最新的3.0標准,所以我自己選擇了3.0,然后很快就掉坑里了(一會兒再說)。
先說下我的工作方式,我使用emacs管理一個全是yaml文件的工程,然后使用$ref把他們都link起來。一開始我每次合並成一個文檔后,然后拿swagger-editor打開,看看哪里有錯誤,再改,但是這樣非常得慢,因為swagger-editor是基於網頁的,本地文件變了不會自動加載到編輯器中去,還得每次點。官方有個swagger-validator貌似只支持2.0的,即使支持3.0,估計我也搞不太明白,因為不習慣nodejs那套東西,終於發現python也有一個叫 openapi-spec-validator的東西,雖然做得粗糙了點,但是仍然是可以用的,很方便集成到我的工作流中,每次保存時合並到一個文件中,然后調用 validator 檢查,非常好。
不管能不能搞明白nodejs,swagger-editor和swagger-ui是必須要使用的工具,幸好官方提供了docker container,然后我再寫一個alias,就可以在bash中使用了,如下
alias swagger-ui='echo "http://localhost:8000" && docker run --rm --name swagger-ui -p 8000:8080 -e SWAGGER_JSON=/app/openapi.yaml -v $PWD:/app swaggerapi/swagger-ui' alias swagger-editor='echo "http://localhost:8080" && docker run --rm --name swagger-editor -p 8080:8080 swaggerapi/swagger-editor'
這里假設了我合並之后的文檔名稱為 openapi.yaml
生成代碼
當我很興奮了寫了很多endpoint之后,我想試試生成代碼這個功能,很不幸,真的被坑了。swagger-codegen穩定版本居然不支持 3.0版本的openapi,只支持到2.0,抱着試一試的心態去看看了正在開發的swagger-codegen的snapshot,太讓人失望了,只支持幾種語言,居然沒有python也沒有go,大約都是java和js。
於是我沒有辦法,又去看了下2.0版本的openapi規范,真心不如3.0,着實沒有學習的動力,萬般無奈下,到處找3.0轉2.0找工具,只有一兩種可選,而且不是收費,就是不好使。最后終於被我在github上發現了api-spec-converter,可以把3.0轉成2.0。在解決了如何不使用root用戶全局安裝npm module后,才把它安裝上了。然后使用命令行
api-spec-converter -f openapi_3 -t swagger_2 openapi.yaml > swagger.json
就可以轉換,我也以為就這樣結束了呢,使用少的東西,坑自己多,由於2.0的表達能力不是很強,外加轉換工具有BUG,所以我列舉了下注意事項如下
- path不能有summary和description,這些應該放到operation里(即get/put/post等里)
- 只支持一個server
- components里只能有schema,不能有其他的,如parameters,responses
- parameter最好不要有local ref,api-spec-converter不能正確處理
- parameter應定義在operation級,即get/put/post下面,公共的parameter,工具處理不正確
- additionalProperties不支持,工具也沒有自動地刪除它
- readOnly的properties不能具有required屬性
終於生成了2.0的spec,有空再試codegen的質量吧。坐等codegen支持3.0,或者哪天我自己研究個Python或Go的工具吧。
總結
不管怎樣,swagger-ui 我還是很喜歡的,api自帶swagger-ui這樣的界面,集文檔和嘗試一身,對用戶非常友好,即使不能生成代碼,也是不錯的選擇。