如何使用代码中的注释从python生成swagger规范文件(json)?

时间:2017-01-08 03:45:51

标签: python documentation tornado swagger-2.0

问题陈述:我希望自动生成JSON API的机器和人类可读规范,以便任何人都可以使用我们的API进行可视化和交互。
一个可行的解决方案是使用OpenAPISpecification(fka swagger)。我无法找到一个易于理解的指南,特别是龙卷风使用招摇,所以我的问题是:

  1. 如何自动从python代码中的注释生成swagger规范文件?
  2. 我还使用JSON schemas进行输入验证,如何将这些与swagger规范集成。
  3. 我的API是用龙卷风4.3在python 2.7.11中编写的。 如果您有任何其他建议,请提出建议,而不是使用招摇。

    更新:Apispec是一个有趣的开始,但它现在不能与JSON模式一起使用,所以不回答我的问题entirely

2 个答案:

答案 0 :(得分:0)

我们最近有这项要求。我们制作了自己的生成器,该生成器从Google样式文档字符串生成OpenAPI 3.0 API规范。您只需要装饰处理程序和模型类即可。有关更多信息:https://pypi.org/project/tornado-swirl/-尽管仍在进行中,但我们正在积极进行中。

import tornado.web
import tornado_swirl as swirl

@swirl.restapi('/item/(?P<itemid>\d+)')
class ItemHandler(tornado.web.RequestHandler):

    def get(self, itemid):
        """Get Item data.

        Gets Item data from database.

        Path Parameter:
            itemid (int) -- The item id
        """
        pass

@swirl.schema
class User(object):
    """This is the user class

    Your usual long description.

    Properties:
        name (string) -- required.  Name of user
        age (int) -- Age of user

    """
    pass



def make_app():
    return swirl.Application(swirl.api_routes())

if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

答案 1 :(得分:0)

我写了一个与python2.7兼容的插件。您可以使用pip install -U tornado-rest-swagger直接安装它。它使用openapi3.0的语法。这是一个示例:

import tornado.ioloop
import tornado.options
import tornado.web

from tornado_swagger.components import components
from tornado_swagger.setup import setup_swagger


class BaseHandler(tornado.web.RequestHandler):
    def data_received(self, chunk):
        pass


class PostsHandler(BaseHandler):
    def get(self):
        """
        ---
        tags:
          - Posts
        summary: List posts
        description: List all posts in feed
        operationId: getPost
        responses:
            '200':
              description: A list of users
              content:
                application/json:
                  schema:
                    $ref: '#/components/schemas/ArrayOfPostModel'
                application/xml:
                  schema:
                    $ref: '#/components/schemas/ArrayOfPostModel'
                text/plain:
                  schema:
                    type: string
        """

    def post(self):
        """
        ---
        tags:
          - Posts
        summary: Add a new Post to the blog
        operationId: addPost
        requestBody:
          description: Post object that needs to be added to the blog
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PostModel'
            application/xml:
              schema:
                $ref: '#/components/schemas/PostModel'
          required: true
        responses:
          '405':
            description: Invalid input
            content: {}
        security:
          - petstore_auth:
              - 'write:pets'
              - 'read:pets'
        """


class PostsDetailsHandler(BaseHandler):
    def get(self, posts_id):
        """
        ---
        tags:
          - Posts
        summary: Find Post by ID
        description: Returns a single post
        operationId: getPostById
        parameters:
          - name: post_id
            in: path
            description: ID of post to return
            required: true
            schema:
              type: integer
              format: int64
        responses:
          '200':
            description: successful operation
            content:
              application/xml:
                schema:
                  $ref: '#/components/schemas/PostModel'
              application/json:
                schema:
                  $ref: '#/components/schemas/PostModel'
          '400':
            description: Invalid ID supplied
            content: {}
          '404':
            description: Pet not found
            content: {}
        security:
          - api_key: []
        """

    def patch(self, posts_id):
        """
        ---
        tags:
          - Posts
        summary: Find Post by ID
        description: Returns a single post
        operationId: getPostById
        parameters:
          - name: post_id
            in: path
            description: ID of post to return
            required: true
            schema:
              type: integer
              format: int64
        requestBody:
          description: Post object that needs to be added to the blog
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PostModel'
            application/xml:
              schema:
                $ref: '#/components/schemas/PostModel'
          required: true
        responses:
          '400':
            description: Invalid ID supplied
            content: {}
          '404':
            description: Pet not found
            content: {}
        security:
          - api_key: []
        """

    def delete(self, posts_id):
        """
        ---
        tags:
          - Posts
        summary: Delete Post by ID
        description: Returns a single post
        operationId: getPostById
        parameters:
          - name: post_id
            in: path
            description: ID of post to return
            required: true
            schema:
              type: integer
              format: int64
        responses:
          '200':
            description: successful operation
            content:
              application/json:
                schema:
                  type: object
                  description: Post model representation
                  properties:
                    id:
                      type: integer
                      format: int64
                    title:
                      type: string
                    text:
                      type: string
                    is_visible:
                      type: boolean
                      default: true
          '400':
            description: Invalid ID supplied
            content: {}
          '404':
            description: Pet not found
            content: {}
        """


@components.schemas.register
class PostModel(object):
    """
    ---
    type: object
    description: Post model representation
    properties:
        id:
            type: integer
            format: int64
        title:
            type: string
        text:
            type: string
        is_visible:
            type: boolean
            default: true
    """


@components.schemas.register
class ArrayOfPostModel(object):
    """
    ---
    type: array
    description: Array of Post model representation
    items:
        $ref: '#/components/schemas/PostModel'
    """


@components.security_schemes.register
class JWTToken(object):
    """
    ---
    type: http
    scheme: bearer
    bearerFormat: JWT
    """


class Application(tornado.web.Application):
    _routes = [tornado.web.url(r"/api/posts", PostsHandler), tornado.web.url(r"/api/posts/(\w+)", PostsDetailsHandler)]

    def __init__(self):
        settings = {"debug": True}

        setup_swagger(
            self._routes,
            swagger_url="/doc",
            description="",
            api_version="1.0.0",
            title="Journal API",
            contact=dict(name="test", email="test@domain.com", url="https://www.cluas.me"),
        )
        super(Application, self).__init__(self._routes, **settings)


if __name__ == "__main__":
    tornado.options.define("port", default="8080", help="Port to listen on")
    tornado.options.parse_command_line()

    app = Application()
    app.listen(port=8080)

    tornado.ioloop.IOLoop.current().start()

如果您的函数是一个装饰器并使用python2.7,则可以尝试用decoratorpip install decorator)包装装饰器,以便获得正确的行为。