1
1
from utils.variant import Variant
2
- from collections import Dict, Optional
2
+ from collections import Dict, List, Optional
3
3
from collections.dict import _DictEntryIter
4
4
5
5
from lightbug_http import NotFound, OK , HTTPService, HTTPRequest, HTTPResponse
6
- from lightbug_http.strings import RequestMethod
6
+ from lightbug_http.http import RequestMethod
7
+ from lightbug_http.uri import URIDelimiters
7
8
8
9
alias MAX_SUB_ROUTER_DEPTH = 20
9
10
@@ -14,15 +15,84 @@ struct RouterErrors:
14
15
alias INVALID_PATH_FRAGMENT_ERROR = " INVALID_PATH_FRAGMENT_ERROR"
15
16
16
17
17
- alias HTTPHandler = fn (req: HTTPRequest) - > HTTPResponse
18
+ alias HTTPHandlerWrapper = fn (req: HTTPRequest) raises escaping - > HTTPResponse
19
+
20
+ # TODO : Placeholder type, what can the JSON container look like
21
+ alias JSONType = Dict[String, String]
22
+
23
+ alias HandlerResponse = Variant[HTTPResponse, String, JSONType]
24
+
25
+
26
+ trait FromReq (Movable , Copyable ):
27
+ fn __init__ (out self , request : HTTPRequest, json : JSONType):
28
+ ...
29
+
30
+ fn from_request (mut self , req : HTTPRequest) raises -> Self:
31
+ ...
32
+
33
+ fn __str__ (self ) -> String:
34
+ ...
18
35
19
36
20
37
@value
21
- struct HandlerMeta :
22
- var handler : HTTPHandler
38
+ struct BaseRequest :
39
+ var request : HTTPRequest
40
+ var json : JSONType
41
+
42
+ fn __init__ (out self , request : HTTPRequest, json : JSONType):
43
+ self .request = request
44
+ self .json = json
23
45
46
+ fn __str__ (self ) -> String:
47
+ return str (" " )
24
48
25
- alias HTTPHandlersMap = Dict[String, HandlerMeta]
49
+ fn from_request (mut self , req : HTTPRequest) raises -> Self:
50
+ return self
51
+
52
+
53
+ @value
54
+ struct RouteHandler[T: FromReq](CollectionElement):
55
+ var handler : fn (T) raises - > HandlerResponse
56
+
57
+ fn __init__ (inout self , h : fn (T) raises - > HandlerResponse):
58
+ self .handler = h
59
+
60
+ fn _encode_response (self , res : HandlerResponse) raises -> HTTPResponse:
61
+ if res.isa[HTTPResponse]():
62
+ return res[HTTPResponse]
63
+ elif res.isa[String]():
64
+ return OK(res[String])
65
+ elif res.isa[JSONType]():
66
+ return OK(self ._serialize_json(res[JSONType]))
67
+ else :
68
+ raise Error(" Unsupported response type" )
69
+
70
+ fn _serialize_json (self , json : JSONType) raises -> String:
71
+ # TODO : Placeholder json serialize implementation
72
+ fn ser (j : JSONType) raises -> String:
73
+ var str_frags = List[String]()
74
+ for kv in j.items():
75
+ str_frags.append(
76
+ ' "' + str (kv[].key) + ' ": "' + str (kv[].value) + ' "'
77
+ )
78
+
79
+ var str_res = str (" {" ) + str (" ," ).join(str_frags) + str (" }" )
80
+ return str_res
81
+
82
+ return ser(json)
83
+
84
+ fn _deserialize_json (self , req : HTTPRequest) raises -> JSONType:
85
+ # TODO : Placeholder json deserialize implementation
86
+ return JSONType()
87
+
88
+ fn handle (self , req : HTTPRequest) raises -> HTTPResponse:
89
+ var payload = T(request = req, json = self ._deserialize_json(req))
90
+ payload = payload.from_request(req)
91
+ var handler_response = self .handler(payload)
92
+ return self ._encode_response(handler_response^ )
93
+
94
+
95
+ alias HTTPHandlersMap = Dict[String, HTTPHandlerWrapper]
26
96
27
97
28
98
@value
@@ -54,7 +124,7 @@ struct RouterBase[is_main_app: Bool = False](HTTPService):
54
124
55
125
fn _route (
56
126
mut self , partial_path : String, method : String, depth : Int = 0
57
- ) raises -> HandlerMeta :
127
+ ) raises -> HTTPHandlerWrapper :
58
128
if depth > MAX_SUB_ROUTER_DEPTH :
59
129
raise Error(RouterErrors.ROUTE_NOT_FOUND_ERROR )
60
130
@@ -63,8 +133,7 @@ struct RouterBase[is_main_app: Bool = False](HTTPService):
63
133
var handler_path = partial_path
64
134
65
135
if partial_path:
66
- # TODO : (Hrist) Update to lightbug_http.uri.URIDelimiters.PATH when available
67
- var fragments = partial_path.split(" /" , 1 )
136
+ var fragments = partial_path.split(URIDelimiters.PATH , 1 )
68
137
69
138
sub_router_name = fragments[0 ]
70
139
if len (fragments) == 2 :
@@ -73,8 +142,7 @@ struct RouterBase[is_main_app: Bool = False](HTTPService):
73
142
remaining_path = " "
74
143
75
144
else :
76
- # TODO : (Hrist) Update to lightbug_http.uri.URIDelimiters.PATH when available
77
- handler_path = " /"
145
+ handler_path = URIDelimiters.PATH
78
146
79
147
if sub_router_name in self .sub_routers:
80
148
return self .sub_routers[sub_router_name]._route(
@@ -87,17 +155,16 @@ struct RouterBase[is_main_app: Bool = False](HTTPService):
87
155
88
156
fn func (mut self , req : HTTPRequest) raises -> HTTPResponse:
89
157
var uri = req.uri
90
- # TODO : (Hrist) Update to lightbug_http.uri.URIDelimiters.PATH when available
91
- var path = uri.path.split(" /" , 1 )[1 ]
92
- var route_handler_meta : HandlerMeta
158
+ var path = uri.path.split(URIDelimiters.PATH , 1 )[1 ]
159
+ var route_handler_meta : HTTPHandlerWrapper
93
160
try :
94
161
route_handler_meta = self ._route(path, req.method)
95
162
except e:
96
163
if str (e) == RouterErrors.ROUTE_NOT_FOUND_ERROR :
97
164
return NotFound(uri.path)
98
165
raise e
99
166
100
- return route_handler_meta.handler (req)
167
+ return route_handler_meta(req)
101
168
102
169
fn _validate_path_fragment (self , path_fragment : String) -> Bool:
103
170
# TODO : Validate fragment
@@ -110,31 +177,51 @@ struct RouterBase[is_main_app: Bool = False](HTTPService):
110
177
fn add_router (mut self , owned router : RouterBase[False ]) raises -> None :
111
178
self .sub_routers[router.path_fragment] = router
112
179
113
- fn add_route (
180
+ # fn register[T: FromReq](inout self, path: String, handler: fn(T) raises):
181
+ #
182
+ # fn handle(req: Request) raises:
183
+ # RouteHandler[T](handler).handle(req)
184
+ #
185
+ # self.routes[path] = handle
186
+ #
187
+ # fn route(self, path: String, req: Request) raises:
188
+ # if path in self.routes:
189
+ # self.routes[path](req)
190
+ # else:
191
+
192
+ fn add_route [
193
+ T : FromReq
194
+ ](
114
195
mut self ,
115
196
partial_path : String,
116
- handler : HTTPHandler ,
197
+ handler : fn (T) raises - > HandlerResponse ,
117
198
method : RequestMethod = RequestMethod.get,
118
199
) raises -> None :
119
200
if not self ._validate_path(partial_path):
120
201
raise Error(RouterErrors.INVALID_PATH_ERROR )
121
- var handler_meta = HandlerMeta(handler)
122
202
123
- self .routes[method.value][partial_path] = handler_meta^
203
+ fn handle (req : HTTPRequest) raises -> HTTPResponse:
204
+ return RouteHandler[T](handler).handle(req)
205
+
206
+ self .routes[method.value][partial_path] = handle^
124
207
125
- fn get (
208
+ fn get [
209
+ T : FromReq = BaseRequest
210
+ ](
126
211
inout self ,
127
212
path : String,
128
- handler : HTTPHandler ,
213
+ handler : fn (T) raises - > HandlerResponse ,
129
214
) raises :
130
- self .add_route(path, handler, RequestMethod.get)
215
+ self .add_route[T] (path, handler, RequestMethod.get)
131
216
132
- fn post (
217
+ fn post [
218
+ T : FromReq = BaseRequest
219
+ ](
133
220
inout self ,
134
221
path : String,
135
- handler : HTTPHandler ,
222
+ handler : fn (T) raises - > HandlerResponse ,
136
223
) raises :
137
- self .add_route(path, handler, RequestMethod.post)
224
+ self .add_route[T] (path, handler, RequestMethod.post)
138
225
139
226
140
227
alias RootRouter = RouterBase[True ]
0 commit comments