Unverified Commit 93ae4f48 authored by cr0hn's avatar cr0hn Committed by GitHub
Browse files

Merge pull request #80 from goranpavlovic/bugfix-data-definitions

Fixed bug with data definitions when want to add nested objects
parents 9e29ad01 df97bc34
......@@ -2,11 +2,19 @@ language: python
sudo: false
python:
- "3.6"
- "3.7"
- "3.8"
env:
- AIOHTTP_VERSION=3.6.2
- AIOHTTP_VERSION=2.3.10
install:
- python setup.py install
- pip install -U pip
- pip install -r requirements-dev.txt
- pip install codecov
- pip install -U codecov
- pip install -q aiohttp==$AIOHTTP_VERSION
script:
- make cov
......
......@@ -83,6 +83,8 @@ def generate_doc_from_each_end_point(
result += " " * indent + str(key) + ':'
if isinstance(value, dict):
result = nesteddict2yaml(value, indent + 2, result + "\n")
elif isinstance(value, str):
result += " \"" + str(value) + "\"\n"
else:
result += " " + str(value) + "\n"
return result
......
......@@ -168,6 +168,65 @@ Global Swagger YAML
web.run_app(app, host="127.0.0.1")
Data Definitions
+++++++++++++++++++
:samp:`aiohttp-swagger` allow to specify data models and to reuse it later when documenting API.
Following example shows how to define nested object and reuse it when writing swagger doc.
.. code-block:: python
@asyncio.coroutine
def users_with_data_def(request):
"""
---
description: This endpoint returns user which is defined though data definition during initialization.
tags:
- Users
produces:
- application/json
responses:
"200":
description: Successful operation, returns User object nested permisiion list
schema:
$ref: '#/definitions/User'
"""
users = fetch_users()
return web.Response(json.dumps(users))
app = web.Application()
app.router.add_route('GET', "/users", users_with_data_def)
setup_swagger(app, definitions={
"User": {
"type": "object",
"properties": {
"username": {
"type": "string",
"description": "User's username name",
"default": "John"
},
"permissions": {
"type": "array",
"items": {
"$ref": "#/definitions/Permission"
}
}
}
},
"Permission": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Permission name"
}
}
}
})
web.run_app(app, host="127.0.0.1")
Nested applications
+++++++++++++++++++
......
-r requirements.txt
pytest
pytest-cov
pytest-aiohttp
flake8
\ No newline at end of file
pytest==5.2.2
pytest-cov==2.8.1
pytest-aiohttp==0.3.0
flake8==3.7.9
\ No newline at end of file
pyyaml
jinja2
aiohttp
\ No newline at end of file
pyYAML==5.1.2
jinja2==2.10.3
aiohttp==3.6.2
\ No newline at end of file
{
"User": {
"type": "object",
"properties": {
"first_name": {
"type": "string",
"description": "User's first name",
"default": "John"
},
"last_name": {
"type": "string",
"description": "User's last name",
"default": "Doe"
},
"permissions": {
"type": "array",
"items": {
"$ref": "#/definitions/Permission"
}
}
},
"required": [
"first_name",
"last_name"
]
},
"Permission": {
"type": "object",
"properties": {
"permission_param_1": {
"type": "string",
"description": "User's permission parameter",
"default": "some_perm"
},
"permission_param_2": {
"type": "string",
"description": "User's permission parameter",
"default": "some_perm"
}
},
"required": [
"permission_param_1",
"permission_param_2"
]
}
}
\ No newline at end of file
......@@ -31,6 +31,24 @@ def undoc_ping(request):
return web.Response(text="pong")
@asyncio.coroutine
def users_with_data_def(request):
"""
---
description: This endpoint returns user which is defined though data definition during initialization.
tags:
- Users
produces:
- application/json
responses:
"200":
description: Successful operation, returns User object nested permisiion list
schema:
$ref: '#/definitions/User'
"""
return web.Response(text="pong")
class ClassView(web.View):
def _irrelevant_method(self):
pass
......@@ -106,8 +124,7 @@ def test_swagger_file_url(test_client, loop):
client = yield from test_client(app)
resp1 = yield from client.get('/api/doc/swagger.json')
assert resp1.status == 200
text = yield from resp1.text()
result = json.loads(text)
result = yield from resp1.json()
assert '/example1' in result['paths']
assert '/example2' in result['paths']
assert 'API Title' in result['info']['title']
......@@ -122,8 +139,7 @@ def test_partial_swagger_file(test_client, loop):
client = yield from test_client(app)
resp1 = yield from client.get('/api/doc/swagger.json')
assert resp1.status == 200
text = yield from resp1.text()
result = json.loads(text)
result = yield from resp1.json()
assert '/ping-partial' in result['paths']
......@@ -142,8 +158,7 @@ def test_custom_swagger(test_client, loop):
client = yield from test_client(app)
resp1 = yield from client.get('/api/v1/doc/swagger.json')
assert resp1.status == 200
text = yield from resp1.text()
result = json.loads(text)
result = yield from resp1.json()
assert '/ping' in result['paths']
assert 'Test Custom Title' in result['info']['title']
......@@ -164,8 +179,7 @@ def test_swagger_home_decorator(test_client, loop):
client = yield from test_client(app)
resp1 = yield from client.get('/api/v1/doc/swagger.json')
assert resp1.status == 200
text = yield from resp1.text()
result = json.loads(text)
result = yield from resp1.json()
assert '/ping' in result['paths']
assert 'Test Custom Title' in result['info']['title']
......@@ -186,8 +200,7 @@ def test_swagger_def_decorator(test_client, loop):
client = yield from test_client(app)
resp1 = yield from client.get('/api/v1/doc/swagger.json')
assert resp1.status == 200
text = yield from resp1.text()
result = json.loads(text)
result = yield from resp1.json()
assert '/ping' in result['paths']
assert 'Test Custom Title' in result['info']['title']
......@@ -210,8 +223,7 @@ def test_swagger_info(test_client, loop, swagger_info):
client = yield from test_client(app)
resp1 = yield from client.get('/api/v1/doc/swagger.json')
assert resp1.status == 200
text = yield from resp1.text()
result = json.loads(text)
result = yield from resp1.json()
assert '/example1' in result['paths']
assert '/example2' in result['paths']
assert 'API Title' in result['info']['title']
......@@ -227,8 +239,7 @@ def test_undocumented_fn(test_client, loop):
assert resp.status == 200
swagger_resp1 = yield from client.get('/api/doc/swagger.json')
assert swagger_resp1.status == 200
text = yield from swagger_resp1.text()
result = json.loads(text)
result = yield from swagger_resp1.json()
assert not result['paths']
......@@ -241,8 +252,7 @@ def test_wrong_method(test_client, loop):
# GET
swagger_resp1 = yield from client.get('/api/doc/swagger.json')
assert swagger_resp1.status == 200
text = yield from swagger_resp1.text()
result = json.loads(text)
result = yield from swagger_resp1.json()
assert "/post_ping" in result['paths']
assert "post" in result['paths']["/post_ping"]
resp = yield from client.get('/post_ping')
......@@ -263,8 +273,7 @@ def test_class_view(test_client, loop):
assert 'OK' in text
swagger_resp1 = yield from client.get('/api/doc/swagger.json')
assert swagger_resp1.status == 200
text = yield from swagger_resp1.text()
result = json.loads(text)
result = yield from swagger_resp1.json()
assert "/class_view" in result['paths']
assert "get" in result['paths']["/class_view"]
assert "post" in result['paths']["/class_view"]
......@@ -274,8 +283,7 @@ def test_class_view(test_client, loop):
assert resp.status == 200
text = yield from resp.text()
assert 'OK' in text
text = yield from swagger_resp1.text()
result = json.loads(text)
result = yield from swagger_resp1.json()
assert "/class_view" in result['paths']
assert "get" in result['paths']["/class_view"]
assert "post" in result['paths']["/class_view"]
......@@ -285,12 +293,29 @@ def test_class_view(test_client, loop):
assert resp.status == 200
text = yield from resp.text()
assert 'OK' in text
text = yield from swagger_resp1.text()
result = json.loads(text)
result = yield from swagger_resp1.json()
assert "/class_view" in result['paths']
assert "patch" not in result['paths']["/class_view"]
@asyncio.coroutine
def test_data_defs(test_client, loop):
TESTS_PATH = abspath(join(dirname(__file__)))
file = open(TESTS_PATH + "/data/example_data_definitions.json")
app = web.Application(loop=loop)
app.router.add_route('GET', "/users", users_with_data_def)
setup_swagger(app, definitions=json.loads(file.read()))
file.close()
client = yield from test_client(app)
swagger_resp1 = yield from client.get('/api/doc/swagger.json')
assert swagger_resp1.status == 200
result = yield from swagger_resp1.json()
assert 'User' in result['definitions']
assert 'Permission' in result['definitions']
assert result['definitions']['User']['properties']['permissions']['items']['$ref'] is not None
@asyncio.coroutine
def test_sub_app(test_client, loop):
sub_app = web.Application(loop=loop)
......@@ -307,8 +332,7 @@ def test_sub_app(test_client, loop):
assert 'OK' in text
swagger_resp1 = yield from client.get('/sub_app/api/doc/swagger.json')
assert swagger_resp1.status == 200
text = yield from swagger_resp1.text()
result = json.loads(text)
result = yield from swagger_resp1.json()
assert "/class_view" in result['paths']
assert "get" in result['paths']["/class_view"]
assert "post" in result['paths']["/class_view"]
[tox]
envlist = py34, py35, py36
envlist = py34, py35, py36, py37, py38
[testenv]
deps = -rrequirements-dev.txt
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment