Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/support swagger #206

Merged
merged 13 commits into from
Oct 26, 2021
9 changes: 8 additions & 1 deletion faust/web/apps/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@

@blueprint.route("/", name="detail")
class Graph(web.View):
"""Render image from graph of running services."""
"""
---
description: Render image from graph of running services.
tags:
- Faust
produces:
- application/json
"""

async def get(self, request: web.Request) -> web.Response:
"""Draw image of the services running in this worker."""
Expand Down
41 changes: 38 additions & 3 deletions faust/web/apps/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@

@blueprint.route("/", name="list")
class TableList(web.View):
"""List routes for all tables."""
"""
---
description: List routes for all tables.
tags:
- Faust
produces:
- application/json
"""

async def get(self, request: web.Request) -> web.Response:
"""Return JSON response with list of all table routes."""
Expand All @@ -19,7 +26,19 @@ async def get(self, request: web.Request) -> web.Response:

@blueprint.route("/{name}/", name="detail")
class TableDetail(web.View):
"""List route for specific table."""
"""
---
description: List route for a specific table.
tags:
- Faust
parameters:
- in: path
name: name
type: string
required: true
produces:
- application/json
"""

async def get(self, request: web.Request, name: str) -> web.Response:
"""Return JSON response with table metadata."""
Expand All @@ -29,7 +48,23 @@ async def get(self, request: web.Request, name: str) -> web.Response:

@blueprint.route("/{name}/{key}/", name="key-detail")
class TableKeyDetail(web.View):
"""List information about key."""
"""
---
description: List information about key.
tags:
- Faust
parameters:
- in: path
name: name
type: string
required: true
- in: path
name: key
type: string
required: true
produces:
- application/json
"""

async def get(self, request: web.Request, name: str, key: str) -> web.Response:
"""Return JSON response after looking up the route of a table key.
Expand Down
18 changes: 16 additions & 2 deletions faust/web/apps/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@

@blueprint.route("/", name="index")
class Stats(web.View):
"""Monitor statistics."""
"""
---
description: Monitor statistics.
tags:
- Faust
produces:
- application/json
"""

async def get(self, request: web.Request) -> web.Response:
"""Return JSON response with sensor information."""
Expand All @@ -26,7 +33,14 @@ async def get(self, request: web.Request) -> web.Response:

@blueprint.route("/assignment/", name="assignment")
class Assignment(web.View):
"""Cluster assignment information."""
"""
---
description: Cluster assignment information.
tags:
- Faust
produces:
- application/json
"""

@classmethod
def _topic_grouped(cls, assignment: Set[TP]) -> TPMap:
Expand Down
41 changes: 38 additions & 3 deletions faust/web/apps/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,14 @@ def get_table_value_or_404(self, table: TableT, key: K) -> V:

@blueprint.route("/", name="list")
class TableList(TableView):
"""List available table names."""
"""
---
description: List available table names.
tags:
- Faust
produces:
- application/json
"""

async def get(self, request: web.Request) -> web.Response:
"""Return JSON response with a list of available table names."""
Expand All @@ -56,7 +63,19 @@ async def get(self, request: web.Request) -> web.Response:

@blueprint.route("/{name}/", name="detail")
class TableDetail(TableView):
"""Get details for table by name."""
"""
---
description: Get details for table by name.
tags:
- Faust
parameters:
- in: path
name: name
type: string
required: true
produces:
- application/json
"""

async def get(self, request: web.Request, name: str) -> web.Response:
"""Return JSON response with table information."""
Expand All @@ -66,7 +85,23 @@ async def get(self, request: web.Request, name: str) -> web.Response:

@blueprint.route("/{name}/{key}/", name="key-detail")
class TableKeyDetail(TableView):
"""List information about key."""
"""
---
description: List information about key.
tags:
- Faust
parameters:
- in: path
name: name
type: string
required: true
- in: path
name: key
type: string
required: true
produces:
- application/json
"""

def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
Expand Down
10 changes: 5 additions & 5 deletions faust/web/drivers/aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,15 +227,14 @@ def route(
cors_options: Mapping[str, ResourceOptions] = None,
) -> None:
"""Add route for web view or handler."""
async_handler = self._wrap_into_asyncdef(handler)
if cors_options or self.cors_options:
async_handler = self._wrap_into_asyncdef(handler)
for method in NON_OPTIONS_METHODS:
for method in NON_OPTIONS_METHODS & handler.get_methods():
r = self.web_app.router.add_route(method, pattern, async_handler)
self.cors.add(r, _prepare_cors_options(cors_options or {}))
else:
self.web_app.router.add_route(
"*", pattern, self._wrap_into_asyncdef(handler)
)
for method in handler.get_methods():
self.web_app.router.add_route(method, pattern, async_handler)

def _wrap_into_asyncdef(self, handler: Callable) -> Callable:
# get rid of pesky "DeprecationWarning: Bare functions are
Expand All @@ -246,6 +245,7 @@ def _wrap_into_asyncdef(self, handler: Callable) -> Callable:
async def _dispatch(request: base.Request) -> base.Response:
return await handler(request)

_dispatch.__doc__ = handler.__doc__
return _dispatch

def add_static(self, prefix: str, path: Union[Path, str], **kwargs: Any) -> None:
Expand Down
20 changes: 20 additions & 0 deletions faust/web/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
Mapping,
MutableMapping,
Optional,
Set,
Type,
Union,
cast,
Expand Down Expand Up @@ -71,12 +72,31 @@ def __init__(self, app: AppT, web: Web) -> None:
"options": self.options,
"search": self.search,
}

self.__post_init__()

def __post_init__(self) -> None:
"""Override this to add custom initialization to your view."""
...

def get_methods(self) -> Set:
"""Return the supported methods for this view"""
methods = set({"HEAD"})
base_methods = {
"head": View.head,
"get": View.get,
"post": View.post,
"patch": View.patch,
"delete": View.delete,
"put": View.put,
"options": View.options,
"search": View.search,
}
for method_name, method in self.methods.items():
if method.__code__ is not base_methods[method_name].__code__:
methods.add(method_name.upper())
return methods

async def __call__(self, request: Any) -> Any:
"""Perform HTTP request."""
return await self.dispatch(request)
Expand Down
9 changes: 7 additions & 2 deletions tests/unit/web/drivers/test_aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@ def test_add_static(self, *, web):

def test_route__with_cors_options(self, *, web):
handler = Mock()
handler.get_methods = Mock(
name="get_methods", return_value=set({"GET", "PUT", "POST", "DELETE"})
)
cors_options = {
"http://example.com": ResourceOptions(
allow_credentials=True,
Expand All @@ -311,15 +314,17 @@ def test_route__with_cors_options(self, *, web):
)

web.web_app.router.add_route.assert_has_calls(
[call(method, "/foo/", ANY) for method in NON_OPTIONS_METHODS]
[call(method, "/foo/", ANY) for method in NON_OPTIONS_METHODS],
any_order=True,
)
web._cors.add.assert_has_calls(
[
call(
web.web_app.router.add_route(), _prepare_cors_options(cors_options)
)
for _ in NON_OPTIONS_METHODS
]
],
any_order=True,
)

def test__create_site(self, *, web, app):
Expand Down
3 changes: 3 additions & 0 deletions tests/unit/web/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ def test_init(self, *, app, web, view):
"search": view.search,
}

def test_get_methods(self, view):
assert view.get_methods() == set({"GET", "HEAD"})

@pytest.mark.parametrize(
"method",
[
Expand Down