Commit 97c656c4 authored by cr0hn's avatar cr0hn
Browse files

Initial commit

parents
# Created by .ignore support plugin (hsz.mobi)
### IPythonNotebook template
# Temporary data
.ipynb_checkpoints/
### VirtualEnv template
# Virtualenv
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
.Python
[Bb]in
[Ii]nclude
[Ll]ib
[Ll]ib64
[Ll]ocal
[Ss]cripts
pyvenv.cfg
.venv
pip-selfcheck.json
### OSX template
*.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# IPython Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# dotenv
.env
# virtualenv
venv/
ENV/
# Spyder project settings
.spyderproject
# Rope project settings
.ropeproject
\ No newline at end of file
Version 1.0.0
=============
Internal modifications
----------------------
- First Version
Improvements and fixes
----------------------
- First Version
New features
------------
- First Version
\ No newline at end of file
Copyright (c) Daniel Garcia (cr0hn)
Project home: https://github.com/cr0hn/aiohttp-swagger
Project contact: cr0hn[at]cr0hn.com
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of Daniel Garcia (cr0hn) nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
include LICENSE CHANGELOG README.md requirements.txt requirements-performance.txt
recursive-include aiohttp_swagger/templates *
recursive-include aiohttp_swagger/swagger_ui *
recursive-exclude * __pycache__
recursive-exclude * *.pyc
recursive-exclude * *.pyo
recursive-exclude * *.orig
recursive-exclude * .DS_Store
global-exclude __pycache__/*
global-exclude .deps/*
global-exclude *.so
global-exclude *.pyd
global-exclude *.pyc
global-exclude .git*
global-exclude .DS_Store
global-exclude .mailmap
prune aiohttp_swagger/doc*
graft aiohttp_swagger/resources/*
aiohttp-swagger
===============
![Logo](aiohttp_swagger/doc/images/logo.png)
*aiohttp-swagger: Swagger API Documentation for aiohttp server*
Code | https://github.com/cr0hn/aiohttp-swagger
---- | ----------------------------------------------
Issues | https://github.com/cr0hn/aiohttp-swagger/issues/
Python version | Python 3.5 and above
What's aiohttp-swagger
----------------------
aiohttp-swagger is a plugin for aiohttp.web server that allow to document APIs using Swagger show the Swagger-ui console.
Installation
------------
Simple
++++++
Install aiohttp-swagger is so easy:
```
$ python3.5 -m pip install aiohttp-swagger
```
With extra performance
++++++++++++++++++++++
Aiohttp-swagger also includes some optional dependencies to add extra performance but requires a bit different installation, because they (usually) depends of C extensions.
To install the tool with extra performance you must do:
```
$ python3.5 -m pip install 'aiohttp-swagger[performance]'
```
**Remember that aiohttp-swagger only runs in Python 3.5 and above**.
Quick start
-----------
Document an API is so simple:
```python
from aiohttp import web
from aiohttp_swagger import *
async def ping(request):
"""
---
description: This end-point allow to test that service is up.
tags:
- Health check
produces:
- text/plain
responses:
"200":
description: successful operation. Return "pong" text
"405":
description: invalid HTTP Method
"""
return web.Response(text="pong")
app = web.Application()
app.router.add_route('GET', "/ping", ping)
setup_swagger(app)
web.run_app(app, host="127.0.0.1")
```
It produces:
![Swagger Ping Example](aiohttp_swagger/doc/images/swagger_ping.jpg)
Adding Swagger from external file
---------------------------------
Per End-Point level
+++++++++++++++++++
We can add the Swagger doc from an external YAML file at end-point level. You only need to decorate the end-point function handler:
```python
from aiohttp import web
from aiohttp_swagger import *
@swagger_path("example_swagger_partial.yaml") # <-- Load Swagger info from external file
async def example_2(request):
"""
Example 3 handler description. This description is only for Sphinx.
"""
return web.Response(text="Example")
async def example_3(request):
"""
Description end-point
"""
return web.Response(text="Example")
app = web.Application()
app.router.add_route('GET', "/example1", example_1)
app.router.add_route('GET', "/example2", example_2)
setup_swagger(app)
web.run_app(app, host="127.0.0.1")
```
External file must have this format:
```yaml
tags:
- user
summary: Create user
description: This can only be done by the logged in user.
operationId: examples.api.api.createUser
produces:
- application/json
parameters:
- in: body
name: body
description: Created user object
required: false
schema:
type: object
properties:
id:
type: integer
format: int64
username:
type:
- "string"
- "null"
firstName:
type: string
lastName:
type: string
email:
type: string
password:
type: string
phone:
type: string
userStatus:
type: integer
format: int32
description: User Status
responses:
"201":
description: successful operation
```
**Pay attention that file doesn't contain information about HTTP Method o End-Point name. This information will be added automatically**.
Global Swagger YAML
+++++++++++++++++++
aiohttp-swagger also allow to build an external YAML Swagger file and load it before:
```python
from aiohttp import web
from aiohttp_swagger import *
async def ping(request):
"""
This is my usually Sphinx doc
>>> import json
>>> ping(None)
:param request: Context injected by aiohttp framework
:type request: RequestHandler
"""
return web.Response(text="pong")
app = web.Application()
app.router.add_route('GET', "/ping", ping)
setup_swagger(app, swagger_from_file="example_swagger.yaml") # <-- Loaded Swagger from external YAML file
web.run_app(app, host="127.0.0.1")
```
F.A.Q.
------
Q: Where start the Swagger documentation in my function doc?
A: aiohttp-swagger try to find the string **---**. When it find this string pattern, the next text until the end of function are considered Swagger doc.
Q: Can I Combine the Swagger documentation with my usually Sphinx doc?
A: Sure! Your Sphinx doc must be first of the **---** limiter.
```python
async def ping(request):
"""
This is my usually Sphinx doc
>>> import json
>>> ping(None)
:param request: Context injected by aiohttp framework
:type request: RequestHandler
---
description: This end-point allow to test that service is up.
tags:
- Health check
produces:
- text/plain
responses:
"200":
description: successful operation. Return "pong" text
"405":
description: invalid HTTP Method
"""
```
Q: How can I group a list of End-Point?
A: End-Point will be grouped by their title. The end-point with the same title will be grouped automatically:
![Swagger title](aiohttp_swagger/doc/images/swagger_title.jpg)
Q: How can I change the Title of a group of End-Points?
A: Swagger has a tag that uses to build the titles. The tag name is **tags**. The format is:
```yaml
tags: # <-- TAG USEF FOR THE TITLE
- Health check
description: This end-point allow to test that service is up.
produces:
- text/plain
responses:
"200":
description: successful operation. Return "pong" text
"405":
description: invalid HTTP Method
```
Q: What happens if I use YAML file and function documentation for build Swagger doc at the same time?
A: If two method are provided, aiohttp-swagger will use the YAML over the function doc.
Swagger Documentation & Examples
--------------------------------
You can read the Swagger parameters and format at:
OpenAPI Spec: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md
If you need more examples, there're some available in at folder: **aiohttp_swagger/examples**.
What's new?
-----------
Version 1.0.0
+++++++++++++
- First version released
You can read entire list in CHANGELOG file.
\ No newline at end of file
from os.path import join, dirname, abspath
from aiohttp import web
from .helpers import swagger_path, generate_doc_from_each_end_point, load_doc_from_yaml_file
async def swagger_home(request):
return web.Response(text=request.app["SWAGGER_TEMPLATE_CONTENT"], content_type="text/html")
async def swagger_def(request):
"""
asdfasf a sf asd f
:param request:
:type request:
:return:
:rtype:
"""
# return web.Response(text=request.app["SWAGGER_DEF_CONTENT"], content_type="application/json")
return web.json_response(text=request.app["SWAGGER_DEF_CONTENT"])
STATIC_PATH = abspath(join(dirname(__file__), "swagger_ui"))
def setup_swagger(app: web.Application,
*,
swagger_from_file: str = None,
swagger_url: str = "/api/doc",
api_base_url: str = "/",
description: str = "Swagger API definition",
api_version: str = "1.0.0",
title: str = "Swagger API",
contact: str = ""):
_swagger_url = "/{}".format(swagger_url) if not swagger_url.startswith("/") else swagger_url
_swagger_def_url = '{}/swagger.json'.format(_swagger_url)
# Build Swagget Info
if swagger_from_file:
swagger_info = load_doc_from_yaml_file(swagger_from_file)
else:
swagger_info = generate_doc_from_each_end_point(app,
api_base_url=api_base_url,
description=description,
api_version=api_version,
title=title,
contact=contact)
# Add API routes
app.router.add_route('GET', _swagger_url, swagger_home)
app.router.add_route('GET', "{}/".format(_swagger_url), swagger_home)
app.router.add_route('GET', _swagger_def_url, swagger_def)
# Set statics
statics_path = '{}/swagger_static'.format(_swagger_url)
app.router.add_static(statics_path, STATIC_PATH)
# --------------------------------------------------------------------------
# Build templates
# --------------------------------------------------------------------------
app["SWAGGER_DEF_CONTENT"] = swagger_info
app["SWAGGER_TEMPLATE_CONTENT"] = open(join(STATIC_PATH, "index.html"), "r").read() \
.replace("##SWAGGER_CONFIG##", _swagger_def_url) \
.replace("##STATIC_PATH##", statics_path)
__all__ = ("setup_swagger", "swagger_path")
from os.path import join, dirname
from aiohttp import web
if __name__ == '__main__':
import os
import sys
parent_dir = os.path.dirname(os.path.dirname(os.path.join("..", os.path.abspath(__file__))))
sys.path.insert(1, parent_dir)
import aiohttp_swagger
__package__ = str("aiohttp_swagger")
from aiohttp_swagger import *
async def example_1(request):
"""
Description end-point
---
tags:
- Example
summary: Create user
description: This can only be done by the logged in user.
operationId: examples.api.api.createUser
produces:
- application/json
parameters:
- in: body
name: body
description: Created user object
required: false
schema:
type: object
properties:
id:
type: integer
format: int64
username:
type:
- "string"
- "null"
firstName:
type: string
lastName:
type: string
email:
type: string
password:
type: string
phone:
type: string
userStatus:
type: integer
format: int32
description: User Status
responses:
"201":
description: successful operation
"""
return web.Response(text="Example")
@swagger_path("example_swagger_partial.yaml")
async def example_2(request):
"""
Description end-point
---
tags:
- Example
summary: Create user
description: This can only be done by the logged in user.
operationId: examples.api.api.createUser
produces:
- application/json
responses:
"302":
description: successful operation
schema:
type: string
headers: