最简洁的方法将生成的Flask应用程序代码(Swagger-Codegen)粘贴到后端实现

时间:2017-08-14 17:58:05

标签: python rest flask swagger swagger-codegen

我有:

  1. 执行[Stuff]
  2. 的库
  3. 一个昂首阔步的API定义,大致相当于#1,只是略有不同,可以干净地映射到REST服务
  4. 使用Swagger-Codegen生成#2的烧瓶应用程序 - 例如,导致python控制器函数与#1大致一对一。
  5. 我的意图是,烧瓶应用程序(所有生成的代码)应该只处理实际REST api和参数解析的映射,以匹配swagger中编码的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()的正确方法是什么?

    当然,如果我对我的swagger规范进行重大更改,我将不得不手动更新未生成的代码;但是我可能想要重新生成我的API有很多原因(例如,添加/优化MyTaskTypeFromSwagger类,或者根本不要检查生成的代码)以及是否必须手动编辑生成的API代码,然后所有这些编辑都被每次重新生成所震撼。

    当然,我可以用例如一个简单的语法编写脚本。 pyparsing;虽然这是我第一次遇到这个问题,但它似乎已经被广泛解决了!

5 个答案:

答案 0 :(得分:5)

以下方法对我有用:

  • 创建了三个目录:

    • src - 我的代码,
    • src-gen代表swagger生成的代码,
    • 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目录。
    • 它创建一个symobolic链接,以便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

答案 1 :(得分:4)

我之前很想使用swagger-codegen并遇到同样的难题。在更新规范之前,一切都很好。虽然你可以使用自定义模板,但这只是一个很大的开销和维护,当我想要的只是一个设计第一个API。

我最终使用了connexion,它使用swagger规范来自动处理路由,编组,验证等.Connexion是基于flask构建的,所以你不必担心切换框架或任何东西,你只会从swagger中自动处理部分应用程序,而不必维护自动生成的代码。

答案 2 :(得分:1)

目前我正在通过这些步骤进行构建来解决这个问题

  1. 运行codegen
  2. sed脚本生成的代码来修复像命名空间这样的简单内容
  3. 手动编辑文件,以便不再返回'do some magic'(即所有生成的控制器端点返回的字符串),而只是在我的后端调用相应的函数'
  4. 使用git format-patch来修改前面的更改,以便在重新生成代码时,构建可以自动应用更改。
  5. 因此,我可以添加新的端点,我只需要将调用手动编码到我的后端〜一次。而不是使用补丁文件,我可以通过为生成的代码编写py解析语法并使用解析后生成的代码创建对我的后端的调用来直接执行此操作...这需要更长的时间,所以我做了所有这些快速破解。

    这远非最佳,我不会将此标记为接受,因为我希望有人能提供真正的解决方案。

答案 3 :(得分:0)

我参加的工作流程。

这个想法是生成代码,然后将swagger_server包解压缩到项目目录。但是要分开使用,将您要编写的控制器保留在单独的目录中,或者(如我所行)在项目根目录中,并在生成后的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

答案 4 :(得分:0)

使用connexion作为建议的@MrName。

我首先开始将其与代码生成器一起使用。

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()添加到现有控制器。我不会丢失现有的服务器逻辑(但是为了以防万一,我还是会备份它)。我还没有尝试对现有路径进行重大更改。