# tornado-swagger

## What is tornado-swagger?
tornado is a wrapper for tornado which enables swagger-ui support.

In essense, you just need to wrap the Api instance and add a few python decorators to
get full swagger support.http://swagger.io/


## How to use:


```python
from tornado.web import RequestHandler, HTTPError
from tornado_swagger import swagger

swagger.docs()

# You may decorate your operation with @swagger.operation and use docs to inform information
class ItemNoParamHandler(GenericApiHandler):
    @swagger.operation(nickname='create')
    def post(self):
        """
            @param body: create test results for a item.
            @type body: L{Item}
            @return 200: item is created.
            @raise 400: invalid input
        """

# Operations not decorated with @swagger.operation do not get added to the swagger docs

class ItemNoParamHandler(GenericApiHandler):
    def options(self):
        """
        I'm not visible in the swagger docs
        """
        pass


# Then you use swagger.Application instead of tornado.web.Application
# and do other operations as usual

def make_app():
    return swagger.Application([
        (r"/items", ItemNoParamHandler),
        (r"/items/([^/]+)", ItemHandler),
        (r"/items/([^/]+)/cases/([^/]+)", ItemOptionParamHandler),
    ])

# You define models like this:
@swagger.model
class Item:
    """
        @descriptin:
            This is an example of a model class that has parameters in its constructor
            and the fields in the swagger spec are derived from the parameters to __init__.
        @notes:
            In this case we would have property1, property2 as required parameters
            and property3 as optional parameter.
        @property property3: Item decription
        @ptype property3: L{PropertySubclass}
    """
    def __init__(self, property1, property2=None):
        self.property1 = property1
        self.property2 = property2

# Swagger json:
    "models": {
        "Item": {
            "description": "A description...",
            "id": "Item",
            "required": [
                "property1",
            ],
            "properties": [
                "property1": {
                    "type": "string"
                },
                "property2": {
                    "type": "string"
                    "default": null
                }
            ]
        }
    }

# If you declare an __init__ method with meaningful arguments
# then those args could be used to deduce the swagger model fields.
# just as shown above

# if you declare an @property in docs, this property property2 will also be used
# to deduce the swagger model fields
class Item:
    """
        @property property3: Item description
    """
    def __init__(self, property1, property2):
        self.property1 = property1
        self.property2 = property2

# Swagger json:
    "models": {
        "Item": {
            "description": "A description...",
            "id": "Item",
            "required": [
                "property1",
            ],
            "properties": [
                "property1": {
                    "type": "string"
                },
                "property2": {
                    "type": "string"
                }
                "property3": {
                    "type": "string"
                }
            ]
        }
    }

# if you declare an argument with @ptype, the type of this argument will be specified
# rather than the default 'string'
class Item:
    """
        @ptype property3: L{PropertySubclass}
    """
    def __init__(self, property1, property2, property3=None):
        self.property1 = property1
        self.property2 = property2
        self.property3 = property3

# Swagger json:
    "models": {
        "Item": {
            "description": "A description...",
            "id": "Item",
            "required": [
                "property1",
            ],
            "properties": [
                "property1": {
                    "type": "string"
                },
                "property2": {
                    "type": "string"
                },
                "property3": {
                    "type": "PropertySubclass"
                    "default": null
                }
            ]
        }
    }

# if you want to declare an list property, you can do it like this:
class Item:
    """
        @ptype property3: L{PropertySubclass}
        @ptype property4: C{list} of L{PropertySubclass}
    """
    def __init__(self, property1, property2, property3, property4=None):
        self.property1 = property1
        self.property2 = property2
        self.property3 = property3
        self.property4 = property4

# Swagger json:
    "models": {
        "Item": {
            "description": "A description...",
            "id": "Item",
            "required": [
                "property1",
            ],
            "properties": [
                "property1": {
                    "type": "string"
                },
                "property2": {
                    "type": "string"
                },
                "property3": {
                    "type": "PropertySubclass"
                    "default": null
                },
                "property4": {
                    "default": null,
                    "items": {
                        "type": "PropertySubclass"},
                        "type": "array"
                    }
                }
            ]
        }
    }

# if it is a query:
class ItemQueryHandler(GenericApiHandler):
    @swagger.operation(nickname='query')
    def get(self):
        """
           @param property1:
           @type property1: L{string}
           @in property1: query
           @required property1: False

           @param property2:
           @type property2: L{string}
           @in property2: query
           @required property2: True
           @rtype: L{Item}

           @notes: GET /item?property1=1&property2=1
        """

# Swagger json:
    "apis": [
        {
            "operations": [
                {
                    "parameters": [
                        {
                            "name": "property1",
                            "dataType": "string",
                            "paramType": "query",
                            "description": ""
                        },
                        {
                            "name": "property2",
                            "dataType": "string",
                            "paramType": "query",
                            "required": true,
                            "description": ""
                        }
                    ],
                    "responseClass": "Item",
                    "notes": null,
                    "responseMessages": [],
                    "summary": null,
                    "httpMethod": "GET",
                    "nickname": "query"
                }
            ],
            "path": "/item",
            "description": null
        },
        ....
    ]
```

# Running and testing

Now run your tornado app

```
python main.py
```

And visit:

```
curl http://ip:port/swagger/spec
```

access to web
```
http://ip:port/swagger/spec.html
```

# Passing more metadata to swagger
customized arguments used in creating the 'swagger.docs' object will be supported later