1- from lightbug_http import HTTPRequest, HTTPResponse, NotFound
21from lightbug_api.service import not_found
2+ from utils.variant import Variant
3+ from collections import Dict, Optional
4+ from collections.dict import _DictEntryIter
5+ from lightbug_http import NotFound, OK , HTTPService, HTTPRequest, HTTPResponse
6+ from lightbug_http.strings import RequestMethod
7+
8+ alias MAX_SUB_ROUTER_DEPTH = 20
9+
10+
11+ struct RouterErrors :
12+ alias ROUTE_NOT_FOUND_ERROR = " ROUTE_NOT_FOUND_ERROR"
13+ alias INVALID_PATH_ERROR = " INVALID_PATH_ERROR"
14+ alias INVALID_PATH_FRAGMENT_ERROR = " INVALID_PATH_FRAGMENT_ERROR"
15+
16+
17+ alias HTTPHandler = fn (req: HTTPRequest) - > HTTPResponse
18+
19+
20+ @value
21+ struct HandlerMeta :
22+ var handler : HTTPHandler
23+
24+
25+ alias HTTPHandlersMap = Dict[String, HandlerMeta]
26+
327
428
529struct APIRoute (CollectionElement ):
@@ -34,10 +58,11 @@ struct APIRoute(CollectionElement):
3458 self .handler = existing.handler
3559 self .operation_id = existing.operation_id^
3660
37-
3861@value
39- struct Router :
40- var routes : List[APIRoute]
62+ struct RouterBase[is_main_app: Bool = False ](HTTPService):
63+ var path_fragment : String
64+ var sub_routers : Dict[String, RouterBase[False ]]
65+ var routes : Dict[String, HTTPHandlersMap]
4166
4267 fn __init__ (out self ):
4368 self .routes = List[APIRoute]()
@@ -52,3 +77,111 @@ struct Router:
5277 out self , path : String, method : String, handler : fn (HTTPRequest) - > HTTPResponse, operation_id : String
5378 ):
5479 self .routes.append(APIRoute(path, method, handler, operation_id))
80+ fn __init__ (out self : Self) raises :
81+ if not is_main_app:
82+ raise Error(" Sub-router requires url path fragment it will manage" )
83+ self .__init__ (path_fragment = " /" )
84+
85+ fn __init__ (out self : Self, path_fragment : String) raises :
86+ self .path_fragment = path_fragment
87+ self .sub_routers = Dict[String, RouterBase[False ]]()
88+ self .routes = Dict[String, HTTPHandlersMap]()
89+
90+ self .routes[RequestMethod.head.value] = HTTPHandlersMap()
91+ self .routes[RequestMethod.get.value] = HTTPHandlersMap()
92+ self .routes[RequestMethod.put.value] = HTTPHandlersMap()
93+ self .routes[RequestMethod.post.value] = HTTPHandlersMap()
94+ self .routes[RequestMethod.patch.value] = HTTPHandlersMap()
95+ self .routes[RequestMethod.delete.value] = HTTPHandlersMap()
96+ self .routes[RequestMethod.options.value] = HTTPHandlersMap()
97+
98+ if not self ._validate_path_fragment(path_fragment):
99+ raise Error(RouterErrors.INVALID_PATH_FRAGMENT_ERROR )
100+
101+ fn _route (
102+ mut self , partial_path : String, method : String, depth : Int = 0
103+ ) raises -> HandlerMeta:
104+ if depth > MAX_SUB_ROUTER_DEPTH :
105+ raise Error(RouterErrors.ROUTE_NOT_FOUND_ERROR )
106+
107+ var sub_router_name : String = " "
108+ var remaining_path : String = " "
109+ var handler_path = partial_path
110+
111+ if partial_path:
112+ # TODO : (Hrist) Update to lightbug_http.uri.URIDelimiters.PATH when available
113+ var fragments = partial_path.split(" /" , 1 )
114+
115+ sub_router_name = fragments[0 ]
116+ if len (fragments) == 2 :
117+ remaining_path = fragments[1 ]
118+ else :
119+ remaining_path = " "
120+
121+ else :
122+ # TODO : (Hrist) Update to lightbug_http.uri.URIDelimiters.PATH when available
123+ handler_path = " /"
124+
125+ if sub_router_name in self .sub_routers:
126+ return self .sub_routers[sub_router_name]._route(
127+ remaining_path, method, depth + 1
128+ )
129+ elif handler_path in self .routes[method]:
130+ return self .routes[method][handler_path]
131+ else :
132+ raise Error(RouterErrors.ROUTE_NOT_FOUND_ERROR )
133+
134+ fn func (mut self , req : HTTPRequest) raises -> HTTPResponse:
135+ var uri = req.uri
136+ # TODO : (Hrist) Update to lightbug_http.uri.URIDelimiters.PATH when available
137+ var path = uri.path.split(" /" , 1 )[1 ]
138+ var route_handler_meta : HandlerMeta
139+ try :
140+ route_handler_meta = self ._route(path, req.method)
141+ except e:
142+ if str (e) == RouterErrors.ROUTE_NOT_FOUND_ERROR :
143+ return NotFound(uri.path)
144+ raise e
145+
146+ return route_handler_meta.handler(req)
147+
148+ fn _validate_path_fragment (self , path_fragment : String) -> Bool:
149+ # TODO : Validate fragment
150+ return True
151+
152+ fn _validate_path (self , path : String) -> Bool:
153+ # TODO : Validate path
154+ return True
155+
156+ fn add_router (mut self , owned router : RouterBase[False ]) raises -> None :
157+ self .sub_routers[router.path_fragment] = router
158+
159+ fn add_route (
160+ mut self ,
161+ partial_path : String,
162+ handler : HTTPHandler,
163+ method : RequestMethod = RequestMethod.get,
164+ ) raises -> None :
165+ if not self ._validate_path(partial_path):
166+ raise Error(RouterErrors.INVALID_PATH_ERROR )
167+ var handler_meta = HandlerMeta(handler)
168+
169+ self .routes[method.value][partial_path] = handler_meta^
170+
171+ fn get (
172+ inout self ,
173+ path : String,
174+ handler : HTTPHandler,
175+ ) raises :
176+ self .add_route(path, handler, RequestMethod.get)
177+
178+ fn post (
179+ inout self ,
180+ path : String,
181+ handler : HTTPHandler,
182+ ) raises :
183+ self .add_route(path, handler, RequestMethod.post)
184+
185+
186+ alias RootRouter = RouterBase[True ]
187+ alias Router = RouterBase[False ]
0 commit comments