@@ -42,6 +42,7 @@ def __init__(
4242 self .conformances = conformances
4343 self .openapi_endpoint_name = openapi_endpoint_name
4444 self .docs_endpoint_name = docs_endpoint_name
45+ self .product_ids : list [str ] = []
4546
4647 # A dict is used to track the product routers so we can ensure
4748 # idempotentcy in case a product is added multiple times, and also to
@@ -140,34 +141,52 @@ def get_root(self, request: Request) -> RootResponse:
140141 def get_conformance (self , request : Request ) -> Conformance :
141142 return Conformance (conforms_to = self .conformances )
142143
143- def get_products (self , request : Request ) -> ProductsCollection :
144+ def get_products (
145+ self , request : Request , next : str | None = None , limit : int = 10
146+ ) -> ProductsCollection :
147+ start = 0
148+ limit = min (limit , 100 )
149+ try :
150+ if next :
151+ start = self .product_ids .index (next )
152+ except ValueError :
153+ logging .exception ("An error occurred while retrieving products" )
154+ raise NotFoundException (
155+ detail = "Error finding pagination token for products"
156+ ) from None
157+ end = start + limit
158+ ids = self .product_ids [start :end ]
159+ links = [
160+ Link (
161+ href = str (request .url_for (f"{ self .name } :list-products" )),
162+ rel = "self" ,
163+ type = TYPE_JSON ,
164+ ),
165+ ]
166+ if end > 0 and end < len (self .product_ids ):
167+ links .append (self .pagination_link (request , self .product_ids [end ]))
144168 return ProductsCollection (
145- products = [pr .get_product (request ) for pr in self .product_routers .values ()],
146- links = [
147- Link (
148- href = str (request .url_for (f"{ self .name } :list-products" )),
149- rel = "self" ,
150- type = TYPE_JSON ,
151- )
169+ products = [
170+ self .product_routers [product_id ].get_product (request )
171+ for product_id in ids
152172 ],
173+ links = links ,
153174 )
154175
155- async def get_orders (self , request : Request ) -> OrderCollection :
156- match await self .backend .get_orders (request ):
157- case Success (orders ):
176+ async def get_orders (
177+ self , request : Request , next : str | None = None , limit : int = 10
178+ ) -> OrderCollection :
179+ links : list [Link ] = []
180+ match await self .backend .get_orders (request , next , limit ):
181+ case Success ((orders , Some (pagination_token ))):
158182 for order in orders :
159- order .links .append (
160- Link (
161- href = str (
162- request .url_for (
163- f"{ self .name } :get-order" , order_id = order .id
164- )
165- ),
166- rel = "self" ,
167- type = TYPE_JSON ,
168- )
169- )
170- return orders
183+ order .links .append (self .order_link (request , order ))
184+ links .append (self .pagination_link (request , pagination_token ))
185+ case Success ((orders , Nothing )): # noqa: F841
186+ for order in orders :
187+ order .links .append (self .order_link (request , order ))
188+ case Failure (ValueError ()):
189+ raise NotFoundException (detail = "Error finding pagination token" )
171190 case Failure (e ):
172191 logger .error (
173192 "An error occurred while retrieving orders: %s" ,
@@ -179,6 +198,7 @@ async def get_orders(self, request: Request) -> OrderCollection:
179198 )
180199 case _:
181200 raise AssertionError ("Expected code to be unreachable" )
201+ return OrderCollection (features = orders , links = links )
182202
183203 async def get_order (self : Self , order_id : str , request : Request ) -> Order :
184204 """
@@ -204,25 +224,21 @@ async def get_order(self: Self, order_id: str, request: Request) -> Order:
204224 raise AssertionError ("Expected code to be unreachable" )
205225
206226 async def get_order_statuses (
207- self : Self , order_id : str , request : Request
227+ self : Self ,
228+ order_id : str ,
229+ request : Request ,
230+ next : str | None = None ,
231+ limit : int = 10 ,
208232 ) -> OrderStatuses :
209- match await self .backend .get_order_statuses (order_id , request ):
210- case Success (statuses ):
211- return OrderStatuses (
212- statuses = statuses ,
213- links = [
214- Link (
215- href = str (
216- request .url_for (
217- f"{ self .name } :list-order-statuses" ,
218- order_id = order_id ,
219- )
220- ),
221- rel = "self" ,
222- type = TYPE_JSON ,
223- )
224- ],
225- )
233+ links : list [Link ] = []
234+ match await self .backend .get_order_statuses (order_id , request , next , limit ):
235+ case Success ((statuses , Some (pagination_token ))):
236+ links .append (self .order_statuses_link (request , order_id ))
237+ links .append (self .pagination_link (request , pagination_token ))
238+ case Success ((statuses , Nothing )): # noqa: F841
239+ links .append (self .order_statuses_link (request , order_id ))
240+ case Failure (KeyError ()):
241+ raise NotFoundException ("Error finding pagination token" )
226242 case Failure (e ):
227243 logger .error (
228244 "An error occurred while retrieving order statuses: %s" ,
@@ -234,12 +250,14 @@ async def get_order_statuses(
234250 )
235251 case _:
236252 raise AssertionError ("Expected code to be unreachable" )
253+ return OrderStatuses (statuses = statuses , links = links )
237254
238255 def add_product (self : Self , product : Product , * args , ** kwargs ) -> None :
239256 # Give the include a prefix from the product router
240257 product_router = ProductRouter (product , self , * args , ** kwargs )
241258 self .include_router (product_router , prefix = f"/products/{ product .id } " )
242259 self .product_routers [product .id ] = product_router
260+ self .product_ids = [* self .product_routers .keys ()]
243261
244262 def generate_order_href (self : Self , request : Request , order_id : str ) -> URL :
245263 return request .url_for (f"{ self .name } :get-order" , order_id = order_id )
@@ -264,3 +282,29 @@ def add_order_links(self, order: Order, request: Request):
264282 type = TYPE_JSON ,
265283 ),
266284 )
285+
286+ def order_link (self , request : Request , order : Order ):
287+ return Link (
288+ href = str (request .url_for (f"{ self .name } :get-order" , order_id = order .id )),
289+ rel = "self" ,
290+ type = TYPE_JSON ,
291+ )
292+
293+ def order_statuses_link (self , request : Request , order_id : str ):
294+ return Link (
295+ href = str (
296+ request .url_for (
297+ f"{ self .name } :list-order-statuses" ,
298+ order_id = order_id ,
299+ )
300+ ),
301+ rel = "self" ,
302+ type = TYPE_JSON ,
303+ )
304+
305+ def pagination_link (self , request : Request , pagination_token : str ):
306+ return Link (
307+ href = str (request .url .include_query_params (next = pagination_token )),
308+ rel = "next" ,
309+ type = TYPE_JSON ,
310+ )
0 commit comments