Search code examples
openapiopenapi-generator

How to generate a Python Flask server with OpenAPI Generator that references my own implementation of *_controller.py?


I want to generate a Python Flask server providing a certain OpenAPI spec as input - let's say foo.yaml - running the following command:

java -jar openapi-generator-cli.jar generate -i foo.yaml -g python-flask -o python-flask_api_server

However, this generates a server stub containing a file called foo_controller.py under \python-flask_api_server\openapi_server\controllers and each method defined in this file returns the same template string:

'do some magic!'

foo_controller.py

def foo_post(inline_object=None):  # noqa: E501
"""Create a foo

 # noqa: E501

:param inline_object: 
:type inline_object: dict | bytes

:rtype: str
"""
if connexion.request.is_json:
    inline_object = InlineObject.from_dict(connexion.request.get_json())  # noqa: E501
return 'do some magic!'

What I'm trying to do with OpenAPI Generator is to generate a server stub whose foo_controller.py references my own implementation of this file, like this for example:

foo_controller.py (generated file)

import foo_controller_impl

def foo_post(inline_object=None):  # noqa: E501
"""Create a foo

 # noqa: E501

:param inline_object: 
:type inline_object: dict | bytes

:rtype: str
"""
foo_controller_impl.foo_post_impl(inline_object)

foo_controller_impl.py (my implementation of foo_controller.py)

def foo_post_impl(inline_object=None):  # noqa: E501
if connexion.request.is_json:
    inline_object = InlineObject.from_dict(connexion.request.get_json())  # noqa: E501
print("Request body is:\n" + str(inline_object))
response = "/foo/1"
return response

I ran the following command to generate a new template set:

java -jar openapi-generator-cli.jar meta -o my-codegen -n myCodegen -p org.openapitools.codegen

But after reading the generated README.md and inspecting MycodegenGenerator.java it still isn't very clear to me how I could achieve this.

Any help would be greatly appreciated.


Solution

  • The solution to my problem was to download Swagger Codegen (link), find the controller.mustache template file for the Python-Flask server (located here: swagger-codegen-master\modules\swagger-codegen\src\main\resources\flaskConnexion) and edit it like this:

    from {{packageName}}.controllers import {{classname}}_impl
    {{#operations}}
    {{#operation}}
    
    
    def {{operationId}}({{#allParams}}{{paramName}}{{^required}}=None{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}):  # noqa: E501
        """{{#summary}}{{.}}{{/summary}}{{^summary}}{{operationId}}{{/summary}}
    
        {{#notes}}{{.}}{{/notes}} # noqa: E501
    
        {{#allParams}}
        :param {{paramName}}: {{description}}
            {{^isContainer}}
                {{#isPrimitiveType}}
        :type {{paramName}}: {{>param_type}}
                {{/isPrimitiveType}}
                {{#isUuid}}
        :type {{paramName}}: {{>param_type}}
                {{/isUuid}}
                {{^isPrimitiveType}}
                    {{#isFile}}
        :type {{paramName}}: werkzeug.datastructures.FileStorage
                    {{/isFile}}
                    {{^isFile}}
                        {{^isUuid}}
        :type {{paramName}}: dict | bytes
                        {{/isUuid}}
                    {{/isFile}}
                {{/isPrimitiveType}}
            {{/isContainer}}
            {{#isListContainer}}
                {{#items}}
                    {{#isPrimitiveType}}
        :type {{paramName}}: List[{{>param_type}}]
                    {{/isPrimitiveType}}
                    {{^isPrimitiveType}}
        :type {{paramName}}: list | bytes
                    {{/isPrimitiveType}}
                {{/items}}
            {{/isListContainer}}
            {{#isMapContainer}}
                {{#items}}
                    {{#isPrimitiveType}}
        :type {{paramName}}: Dict[str, {{>param_type}}]
                    {{/isPrimitiveType}}
                    {{^isPrimitiveType}}
        :type {{paramName}}: dict | bytes
                    {{/isPrimitiveType}}
                {{/items}}
            {{/isMapContainer}}
        {{/allParams}}
    
        :rtype: {{#returnType}}{{.}}{{/returnType}}{{^returnType}}None{{/returnType}}
        """
        return {{classname}}_impl.{{operationId}}({{#allParams}}{{paramName}}{{^required}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
    {{/operation}}
    {{/operations}}
    

    Finally, I used the following command to generate the Python-Flask server:

    java -jar swagger-codegen-cli-2.3.1.jar generate -i foo.yaml -l python-flask -o "swagger server\foo" -t swagger-codegen-master\modules\swagger-codegen\src\main\resources\flaskConnexion
    

    Credit goes to Dudi for his answer to a similar question.