Skip to content

Commit

Permalink
fix path params schema
Browse files Browse the repository at this point in the history
  • Loading branch information
Черемушкин Вячеслав committed Jul 25, 2019
1 parent 35cd39f commit 9cf7231
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 11 deletions.
16 changes: 7 additions & 9 deletions star_resty/apidocs/setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import inspect
import logging
import re
from typing import Dict, Optional, Sequence, Type, Union

from apispec import APISpec
Expand All @@ -13,7 +12,7 @@
from star_resty.method import Method
from star_resty.method.meta import MethodMetaOptions
from star_resty.method.request_parser import RequestParser
from .utils import resolve_schema_name
from .utils import convert_path, resolve_schema_name

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -52,9 +51,12 @@ def generate_api_docs(_: Request):
return UJSONResponse(spec.to_dict())


def get_open_api_version(openapi_version: str) -> int:
v = openapi_version.split('.', maxsplit=1)[0]
return int(v)
def get_open_api_version(version: str) -> int:
v = version.split('.', maxsplit=1)[0]
try:
return int(v)
except (ValueError, TypeError):
raise ValueError(f'Invalid open api version: {version}')


def setup_paths(app: Starlette, spec: APISpec, version: int = 2,
Expand Down Expand Up @@ -187,7 +189,3 @@ def create_error_schema_by_exc(e: Union[Exception, Type[Exception]]) -> Dict:
schema['schema'] = error_schema

return schema


def convert_path(path: str) -> str:
return re.sub(r'<([^>]+)>', r'{\1}', path)
7 changes: 6 additions & 1 deletion star_resty/apidocs/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import inspect
import re
from typing import Any

__all__ = ('resolve_schema_name',)
__all__ = ('resolve_schema_name', 'convert_path')


def resolve_schema_name(schema: Any) -> str:
Expand All @@ -12,3 +13,7 @@ def resolve_schema_name(schema: Any) -> str:

name = f'{cls.__module__}.{cls.__qualname__}'
return name


def convert_path(path: str) -> str:
return re.sub(r'{([^:]+).*}', r'{\1}', path)
62 changes: 61 additions & 1 deletion tests/test_apidocs.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from starlette.applications import Starlette
from starlette.routing import Mount, Route, Router
from starlette.testclient import TestClient

from star_resty.apidocs import setup_spec
from .utils.method import CreateUser
from .utils.method import CreateUser, GetUser, SearchUser


def test_generate_api_docs():
Expand Down Expand Up @@ -44,3 +45,62 @@ def test_generate_api_docs():
'type': 'integer'},
'name': {'type': 'string'}},
'type': 'object'}}


def test_generate_api_docs_for_router():
routes = [
Mount('/v1', Router([
Route('/users', CreateUser.as_endpoint(), methods=['POST']),
Route('/users', SearchUser.as_endpoint(), methods=['GET'])
]))
]
app = Starlette(routes=routes)

setup_spec(app, title='test')

client = TestClient(app)
resp = client.get('/apidocs.json')
assert resp is not None
body = resp.json()
assert body is not None
assert body.get('paths') == {
'/v1/users': {
'post': {'tags': ['users'], 'description': 'create user', 'produces': ['application/json'],
'parameters': [
{'in': 'path', 'name': 'id', 'required': True, 'type': 'integer', 'format': 'int32'},
{'in': 'body', 'required': False, 'name': 'body',
'schema': {'$ref': '#/definitions/tests.utils.method.BodySchema'}}],
'responses': {
'201': {'schema': {'$ref': '#/definitions/tests.utils.method.CreateUserResponse'}},
'400': {'description': 'Bad request'}}},
'get': {'tags': ['default'], 'produces': ['application/json'],
'parameters': [
{'in': 'path', 'name': 'id', 'required': True, 'type': 'integer', 'format': 'int32'},
{'in': 'query', 'name': 'q', 'required': False, 'type': 'string'}],
'responses': {
'200': {'schema': {'$ref': '#/definitions/tests.utils.method.SearchUserResponse'}},
'400': {'description': 'Bad request'}}}}}


def test_generate_api_docs_for_path():
app = Starlette()

setup_spec(app, title='test')
app.add_route('/users/{user_id:int}', GetUser.as_endpoint(), methods=['POST'])

client = TestClient(app)
resp = client.get('/apidocs.json')
assert resp is not None
body = resp.json()
assert body is not None
assert body.get('paths') == {
'/users/{user_id}': {
'post': {
'tags': ['users'], 'description': 'get user', 'produces': ['application/json'],
'parameters': [
{'in': 'path', 'name': 'id', 'required': True, 'type': 'integer', 'format': 'int32'},
{'in': 'body', 'required': False, 'name': 'body',
'schema': {'$ref': '#/definitions/tests.utils.method.BodySchema'}}],
'responses': {
'200': {'schema': {'$ref': '#/definitions/tests.utils.method.CreateUserResponse'}},
'400': {'description': 'Bad request'}}}}}
9 changes: 9 additions & 0 deletions tests/utils/method.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ async def execute(self, user: path(PathParams),
return {'id': user['id'], **payload}


class GetUser(Method):
meta = Operation(tag='users', description='get user')
response_schema = CreateUserResponse

async def execute(self, user: path(PathParams),
payload: json_payload(BodySchema)):
return {'id': 1}


class SearchUser(Method):
mata = Operation(tag='users', description='search user')
response_schema = SearchUserResponse
Expand Down

0 comments on commit 9cf7231

Please sign in to comment.