|
@@ -1,9 +1,8 @@
|
1
|
1
|
# coding: utf-8
|
2
|
|
-import asyncio
|
3
|
2
|
import json
|
|
3
|
+import re
|
4
|
4
|
import typing
|
5
|
5
|
from http import HTTPStatus
|
6
|
|
-from json import JSONDecodeError
|
7
|
6
|
|
8
|
7
|
from aiohttp.web_request import Request
|
9
|
8
|
from aiohttp.web_response import Response
|
|
@@ -12,13 +11,22 @@ from multidict import MultiDict
|
12
|
11
|
from hapic.context import BaseContext
|
13
|
12
|
from hapic.context import RouteRepresentation
|
14
|
13
|
from hapic.decorator import DecoratedController
|
15
|
|
-from hapic.error import ErrorBuilderInterface, DefaultErrorBuilder
|
16
|
|
-from hapic.exception import WorkflowException, OutputValidationException
|
|
14
|
+from hapic.decorator import DECORATION_ATTRIBUTE_NAME
|
|
15
|
+from hapic.error import ErrorBuilderInterface
|
|
16
|
+from hapic.error import DefaultErrorBuilder
|
|
17
|
+from hapic.exception import WorkflowException
|
|
18
|
+from hapic.exception import OutputValidationException
|
|
19
|
+from hapic.exception import NoRoutesException
|
|
20
|
+from hapic.exception import RouteNotFound
|
17
|
21
|
from hapic.processor import ProcessValidationError
|
18
|
22
|
from hapic.processor import RequestParameters
|
19
|
23
|
from aiohttp import web
|
20
|
24
|
|
21
|
25
|
|
|
26
|
+# Bottle regular expression to locate url parameters
|
|
27
|
+AIOHTTP_RE_PATH_URL = re.compile(r'{([^:<>]+)(?::[^<>]+)?}')
|
|
28
|
+
|
|
29
|
+
|
22
|
30
|
class AiohttpRequestParameters(object):
|
23
|
31
|
def __init__(
|
24
|
32
|
self,
|
|
@@ -137,15 +145,48 @@ class AiohttpContext(BaseContext):
|
137
|
145
|
self,
|
138
|
146
|
decorated_controller: DecoratedController,
|
139
|
147
|
) -> RouteRepresentation:
|
140
|
|
- # TODO BS 2018-07-15: to do
|
141
|
|
- raise NotImplementedError('todo')
|
|
148
|
+ if not len(self.app.router.routes()):
|
|
149
|
+ raise NoRoutesException('There is no routes in your aiohttp app')
|
|
150
|
+
|
|
151
|
+ reference = decorated_controller.reference
|
|
152
|
+
|
|
153
|
+ for route in self.app.router.routes():
|
|
154
|
+ route_token = getattr(
|
|
155
|
+ route.handler,
|
|
156
|
+ DECORATION_ATTRIBUTE_NAME,
|
|
157
|
+ None,
|
|
158
|
+ )
|
|
159
|
+
|
|
160
|
+ match_with_wrapper = route.handler == reference.wrapper
|
|
161
|
+ match_with_wrapped = route.handler == reference.wrapped
|
|
162
|
+ match_with_token = route_token == reference.token
|
|
163
|
+
|
|
164
|
+ # TODO BS 2018-07-27: token is set in HEAD view to, must solve this
|
|
165
|
+ # case
|
|
166
|
+ if not match_with_wrapper \
|
|
167
|
+ and not match_with_wrapped \
|
|
168
|
+ and match_with_token \
|
|
169
|
+ and route.method.lower() == 'head':
|
|
170
|
+ continue
|
|
171
|
+
|
|
172
|
+ if match_with_wrapper or match_with_wrapped or match_with_token:
|
|
173
|
+ return RouteRepresentation(
|
|
174
|
+ rule=self.get_swagger_path(route.resource.canonical),
|
|
175
|
+ method=route.method.lower(),
|
|
176
|
+ original_route_object=route,
|
|
177
|
+ )
|
|
178
|
+ # TODO BS 20171010: Raise exception or print error ? see #10
|
|
179
|
+ raise RouteNotFound(
|
|
180
|
+ 'Decorated route "{}" was not found in aiohttp routes'.format(
|
|
181
|
+ decorated_controller.name,
|
|
182
|
+ )
|
|
183
|
+ )
|
142
|
184
|
|
143
|
185
|
def get_swagger_path(
|
144
|
186
|
self,
|
145
|
187
|
contextualised_rule: str,
|
146
|
188
|
) -> str:
|
147
|
|
- # TODO BS 2018-07-15: to do
|
148
|
|
- raise NotImplementedError('todo')
|
|
189
|
+ return AIOHTTP_RE_PATH_URL.sub(r'{\1}', contextualised_rule)
|
149
|
190
|
|
150
|
191
|
def by_pass_output_wrapping(
|
151
|
192
|
self,
|