2022/1/12

swagger codegen , disable normalize (and install)

openapi 規定了 restful api 的描述格式 (json,xml,yml)。
然後 swagger 就做了 codegen,依據openapi 的描述文件產生 restful server 的 code。
依照 server site 使用的語言和 package,產生不同的code。

swagger 官方的 codegen 是用 java 寫的,很不方便(實際用起來就是麻煩,要裝舊版 jdk 跟 maven)。
有人用 python 寫了for python 的 codegen,支援一些python web server framework。
這篇就是用 flask 為例子。
用 "-tlp, --templates" 可以指定產出 flask/tornado/falcon 的 code,default 是 flask。

也就說:
  • 依照openapi 寫 api.json/xml/yml
  • 用 swagger_py_codegen 依照剛剛的 api.XXX 產生 flask 的 code
  • 用 python 來 run 剛剛產生的 code
這樣就有提供你寫好的 api.XXX 的 restful server 了。



依照這說明,啟動 flask restful serve
因為要 python3 (python 2.17 pip install 好,run swagger-py-codegen 會出現 No module named abc 的 error),所以用 conda
conda create -n flaskenv python=3.6
conda repo 有 flask,沒有 swagger-py-codegen。
要用 pip install,所以用 conda install pip (因為 python version 和 host 不一樣)。
再用
pip install swagger-py-codegen
然後抄上面 ref的 api.json:
{
    "swagger": "2.0",
    "info": {
        "version": "1.0.0",
        "title": "Simple API",
        "description": "A simple API to learn how to write OpenAPI Specification"
    },
    "schemes": [
        "https"
    ],
    "host": "simple.api",
    "basePath": "/openapi101",
    "paths": {
        "/persons": {
            "get": {
                "summary": "Gets some persons",
                "description": "Returns a list containing all persons.",
                "responses": {
                    "200": {
                        "description": "A list of Person",
                        "schema": {
                            "type": "array",
                            "items": {
                                "properties": {
                                    "firstName": {
                                        "type": "string"
                                    },
                                    "lastName": {
                                        "type": "string"
                                    },
                                    "username": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
就可以generate flask code:
swagger-py-codegen --swagger-doc api.json example-app
接著安裝 requirement.txt 需要的module
然後用 python run __init__.py 就可以用 browser 測試:
http://localhost:5000/openapi101/persons
因為 code gen 的 code 都是空的,所以內容只有 '[]',可以修改 person.py 的 get(self) 的 return 內容,
就會反應在 browser 上。

codegen 有做 return value 的查核,不符合 api.json 的就會被濾掉。
如果不要濾掉,就要 bypass normalize():
diff --git a/example-app/example_app/openapi101/schemas.py b/example-app/example_app/openapi101/schemas.py
index 86571b5..7ca6cbd 100644
--- a/example-app/example_app/openapi101/schemas.py
+++ b/example-app/example_app/openapi101/schemas.py
@@ -226,4 +226,4 @@ def normalize(schema, data, required_defaults=None, resolver=None):
 
         return funcs[type_](schema, data)
 
-    return _normalize(schema, data), errors
+    return data, errors

normailze( ) 會依照 api.json 內容,針對 return 內容 filter,只把符合的項目留下來。


上面的例子,只會產生 rest4 server,不會產生 swagger 的 操作頁面。
要加上--ui 才會。

加上 --spec 的話,會出現 Error:
  File "/usr/lib/python3.6/json/encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'date' is not JSON serializable
這個要修改swagger_py_codegen 的 code 才行,參考這一篇修改code, build, install。

除此之外,用 python 3.6.9(10,11,13) 都 OK.(update: 20221219 有些3.6都不行了)
使用 3.7.13 也可以。
不過, 在同一個環境 pip install flask 的話, 會出現 Error:
Installing collected packages: zipp, typing-extensions, importlib-metadata, Werkzeug, itsdangerous, click, flask
  Attempting uninstall: click
    Found existing installation: click 6.7
    Uninstalling click-6.7:
      Successfully uninstalled click-6.7
ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
swagger-py-codegen 0.4.0 requires click<7, but you have click 8.1.3 which is incompatible.
Successfully installed Werkzeug-2.1.2 click-8.1.3 flask-2.1.2 importlib-metadata-4.11.4 itsdangerous-2.1.2 typing-extensions-4.2.0 zipp-3.8.0
這樣install flask 完,run swagger_py_codegen 會出現 error 在 click
  File "/home/charles-chang/miniconda3/envs/swagger37/lib/python3.7/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
TypeError: generate() got an unexpected keyword argument 'spec'
所以...
swagger-py-codegen 跟 flask 不能同時 install 在同一個 env 中。因為要求的 click 版本不一樣。

如果在 python 2.7 下 run swagger_py_codegen ,會出現 Error:
  File "/home/charles-chang/.local/lib/python2.7/site-packages/dpath/util.py", line 1, in <module>
    from collections.abc import MutableMapping
ImportError: No module named abc

2022/12/19 更新:

這時候,用 conda create new env python=3.6 的話,pip install swagger_py_codegen 後,run codegen 已經會出錯了:
Traceback (most recent call last):
  File "/home/charles-chang/miniconda3/envs/swagger3.6/bin/swagger_py_codegen", line 5, in 
    from swagger_py_codegen import generate
  File "/home/charles-chang/miniconda3/envs/swagger3.6/lib/python3.6/site-packages/swagger_py_codegen/__init__.py", line 4, in 
    from .command import generate  # noqa
  File "/home/charles-chang/miniconda3/envs/swagger3.6/lib/python3.6/site-packages/swagger_py_codegen/command.py", line 18, in 
    from swagger_spec_validator import SwaggerValidationError
  File "/home/charles-chang/miniconda3/envs/swagger3.6/lib/python3.6/site-packages/swagger_spec_validator/__init__.py", line 1, in 
    from swagger_spec_validator.common import SwaggerValidationError
  File "/home/charles-chang/miniconda3/envs/swagger3.6/lib/python3.6/site-packages/swagger_spec_validator/common.py", line 1
    from __future__ import annotations
    ^
SyntaxError: future feature annotations is not defined
用 python 3.7 就沒問題。
另外列出 python3.7 pip install swagger_py_codegen 後的 package version:
# packages in environment at /home/charles-chang/miniconda3/envs/swagger3.7:
#
# Name                    Version                   Build  Channel
_libgcc_mutex             0.1                        main
_openmp_mutex             5.1                       1_gnu
ca-certificates           2022.10.11           h06a4308_0
certifi                   2022.9.24        py37h06a4308_0
click                     6.7                      pypi_0    pypi
dpath                     2.1.3                    pypi_0    pypi
jinja2                    3.1.2                    pypi_0    pypi
json-spec                 0.10.1                   pypi_0    pypi
jsonschema                2.6.0                    pypi_0    pypi
ld_impl_linux-64          2.38                 h1181459_1
libffi                    3.4.2                h6a678d5_6
libgcc-ng                 11.2.0               h1234567_1
libgomp                   11.2.0               h1234567_1
libstdcxx-ng              11.2.0               h1234567_1
markupsafe                2.1.1                    pypi_0    pypi
ncurses                   6.3                  h5eee18b_3
openssl                   1.1.1s               h7f8727e_0
pip                       22.3.1           py37h06a4308_0
python                    3.7.15               h7a1cb2a_1
pyyaml                    4.2b1                    pypi_0    pypi
readline                  8.2                  h5eee18b_0
setuptools                65.5.0           py37h06a4308_0
six                       1.16.0                   pypi_0    pypi
sqlite                    3.40.0               h5082296_0
swagger-py-codegen        0.4.0                    pypi_0    pypi
swagger-spec-validator    3.0.3                    pypi_0    pypi
tk                        8.6.12               h1ccaba5_0
typing-extensions         4.4.0                    pypi_0    pypi
wheel                     0.37.1             pyhd3eb1b0_0
xz                        5.2.8                h5eee18b_0
zlib                      1.2.13               h5eee18b_0

沒有留言:

張貼留言