簡體   English   中英

將生成的Flask應用程序代碼(Swagger-Codegen)粘合到后端實現的最簡潔方法

[英]cleanest way to glue generated Flask app code (Swagger-Codegen) to backend implementation

我有:

  1. 有[資料]的圖書館
  2. 醒目的API定義,大約是#1,有一些細微差別,可以清晰地映射到REST服務
  3. 一個使用Swagger-Codegen生成的#2燒瓶應用程序-例如,導致#1大致與Python控制器功能一對一。

我的意圖是,flask應用程序(所有生成的代碼)應僅處理實際REST api和參數解析的映射,以匹配以大方的方式編碼的API規范。 在解析完任何參數(再次生成的代碼)之后,它應該直接調用我的(非生成的)后端。

我的問題是,如何最好地不手工編輯生成的python / flask代碼? (反饋我的設計,或完成此工作的正式設計模式的細節也很棒;我是這個領域的新手)。

從生成器開始,我最終得到了python函數,例如:

def create_task(myTaskDefinition):
    """
    comment as specified in swagger.json
    :param myTaskDefinition: json blah blah blah
    :type myTaskDefinition: dict | bytes
    :rtype: ApiResponse
    """
    if connexion.request.is_json:
        myTaskDefinition = MyTaskTypeFromSwagger.from_dict(connexion.request.get_json())
    return 'do some magic!' # swagger codegen inserts this string :)

在后端,我有實際的邏輯:

def create_task_backend(myTaskDefinition):
    # hand-coded, checked into git: do all the things
    return APIResponse(...)

什么是使create_task()調用create_task_backend()的正確方法?

當然,如果我對搖搖欲墜的規格進行了重大更改,則無論如何我都必須手動更新未生成的代碼。 但是,出於多種原因,我可能想重新生成我的API(例如,添加/優化MyTaskTypeFromSwagger類,或者完全跳過git生成的代碼),如果我必須手動編輯生成的API代碼,則所有每次重新生成時,這些編輯都會被刪除。

當然,我可以使用例如〜的簡單語法編寫腳本。 剖析 但是,盡管這是我第一次遇到此問題,但似乎已經被廣泛解決了!

以下方法對我有用:

  • 創建了三個目錄:

    • src對於我的代碼,
    • src-gen生成的代碼
    • codegen中,我已經把那有幾個竅門生成服務器的腳本。
  • 我將所有模板(可在swagger構建中使用)復制到codegen/templates並編輯controller.mustache以引用src/server_impl ,因此它可以使用我自己的代碼。 編輯使用模板語言,因此它是通用的。 它仍然不是完美的(我會更改一些命名約定),但是確實可以。 因此,首先添加到controller.mustache

from {{packageName}}.server_impl.controllers_impl import {{classname}}_impl

然后添加而不是return 'do some magic!' 下列:

return {{classname}}_impl.{{operationId}}({{#allParams}}{{paramName}}{{^required}}=None{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
  • 腳本:
    • src有一個server_impl目錄。
    • 它創建一個符號鏈接,以便server_impl可以作為python模塊導入
cd ../src-gen/swagger_server/
ln -s ../../src/server_impl/
cd ../../codegen
java -jar swagger-codegen-cli.jar generate  \
-i /path_to_your_swagger definition.yaml \
-l python-flask \
-o ../src-gen \
-t ./templates
cd ../src-gen/
python3 -m swagger_server

以前我很想使用swagger-codegen並遇到相同的難題。 一切正常,直到您更新規格。 盡管您可以使用自定義模板,但是當我想要的只是設計優先的API時,這似乎需要大量的開銷和維護。

我最終使用了connexion ,它使用了swagger規范來自動處理路由,封送處理,驗證等。Connexion構建在flask上,因此您不必擔心切換框架或其他任何事情,您將獲得部分收益可以自動處理所有應用程序,而不必維護自動生成的代碼。

現在,我正在按以下步驟進行構建,以解決此問題

  1. 運行代碼
  2. sed-script生成的代碼可修復諸如名稱空間之類的瑣碎內容
  3. 手動編輯文件,以使它們無需返回'do some magic' (即所有生成的控制器端點返回的字符串),而只需在我的“后端”中調用相應的函數
  4. 使用git format-patch對先前的更改進行修補,以便在我重新生成代碼時,構建可以自動應用更改。

因此,我可以添加新的端點,並且只需要手動將調用編碼到后端即可。 無需使用補丁文件,我可以直接通過為生成的代碼編寫py解析語法並使用解析的生成的代碼來創建對我的后端的調用來直接執行此操作……這將花費更長的時間,因此我很快就做了所有這些駭客。

這遠非最佳,我不會將其標記為已接受,因為我希望有人會提供真正的解決方案。

我參加的工作流程。

這個想法是生成代碼,然后將swagger_server包解壓縮到項目目錄。 但是要分開使用,將您正在編寫的控制器保留在單獨的目錄中,或者(如我所做的那樣)在項目根目錄中,並在每代之后使用git merge-files 它們與生成的控制器git merge-files 然后,您需要新的控制器代碼注入swagger_server/controllers ,即在啟動服務器之前。

project
+-- swagger_server
|   +-- controllers
|       +-- controller.py <- this is generated
+-- controller.py <- this is you are typing your code in
+-- controller.py.common <- common ancestor, see below
+-- server.py <- your server code, if any

因此,工作流程如下:

  1. 生成代碼,將swagger_server復制到您的項目目錄,完全覆蓋現有文件
  2. 從項目根目錄備份controller.pycontroller.py.common
  3. git merge-file controller.py controller.py.common swagger_server/controllers/controller.py
  4. swagger_server/controllers/controller.py設為新的共同祖先,然后將其復制到controller.py.common ,覆蓋現有的

隨意使用shell腳本自動化所有這些操作,即

#!/bin/bash
# Swagger generate server and client stub based on specification, them merge it into the project.
# Use carefully! Commit always before using this script!
# The following structure is assumed:
# .
# +-- my_client
# |   +-- swagger_client
# +-- my_server
# |   +-- swagger_server
# +-- merge.sh <- this script

read -p "Have you commited the project??? " -n 1 -r
if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo 'Commit first!'; exit 1; fi

rm -rf swagger-python-client
rm -rf swagger-python-server

java -jar swagger-codegen-cli.jar generate -i swagger.yaml -l python -o swagger-python-client 
java -jar swagger-codegen-cli.jar generate -i swagger.yaml -l python-flask -o swagger-python-server

# Client - it's easy, just replace swagger_client package
rm -rf my_client/swagger_client
cp -rf swagger-python-client/swagger_client/ my_client

# Server - replace swagger_server package and merge with controllers
rm -rf my_server/.backup
mkdir -p my_server/.backup
cp -rf my_server/swagger_server my_server/.backup


rm -rf my_server/swagger_server
cp -rf swagger-python-server/swagger_server my_server


cd my_server/swagger_server/controllers/
files=$( ls * )
cd ../../..

for f in $files; do

    # skip __init__.py
    if [ -z "$flag" ]; then flag=1; continue; fi
    echo "======== $f"

    # initialization
    cp -n my_server/swagger_server/controllers/$f my_server/$f.common
    cp -n my_server/swagger_server/controllers/$f my_server/$f


    # real merge
    cp -f my_server/$f my_server/.backup/
    cp -f my_server/$f.common my_server/.backup/
    git merge-file my_server/$f my_server/$f.common my_server/swagger_server/controllers/$f
    cp -f my_server/swagger_server/controllers/$f otmini-repo/$f.common

done

rm -rf swagger-python-client
rm -rf swagger-python-server

建議使用connexion作為@MrName。

我首先開始將其與Codegen一起使用。

openapi-generator generate -i ../myapi.yaml -g python-flask -o .

這將使用openapi服務器生成目錄。

  |- openapi_server\
      |--controllers\
           |--mytag._controller.py\
      |--openapi\
           |--my-api.yaml\

如果您將標簽添加到api規范中的路徑中,則會為每個標簽創建一個單獨的tagname-controller.py。 對於每個operationId,都會生成一個函數。

但是,一旦設置完成,connexion就可以處理對api規范的更新。 如果我使用operationId = new_func將新路徑添加到openapi / my-api.yaml,則可以將new_func()添加到現有控制器。 我不會丟失現有的服務器邏輯(但是為了以防萬一,我還是會備份它)。 我還沒有嘗試對現有路徑進行重大更改。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM