1414 Response ,
1515 status ,
1616)
17+ from fastapi .responses import JSONResponse
1718from geojson_pydantic .geometries import Geometry
1819from returns .maybe import Maybe , Some
1920from returns .result import Failure , Success
@@ -48,7 +49,7 @@ def get_preference(prefer: str | None = Header(None)) -> str | None:
4849 detail = f"Invalid Prefer header value: { prefer } " ,
4950 )
5051
51- return prefer
52+ return Prefer ( prefer )
5253
5354
5455class ProductRouter (APIRouter ):
@@ -129,7 +130,10 @@ async def _create_order(
129130 tags = ["Products" ],
130131 )
131132
132- if product .supports_opportunity_search :
133+ if (
134+ product .supports_opportunity_search
135+ or root_router .supports_async_opportunity_search
136+ ):
133137 self .add_api_route (
134138 path = "/opportunities" ,
135139 endpoint = self .search_opportunities ,
@@ -141,21 +145,17 @@ async def _create_order(
141145 Geometry ,
142146 self .product .opportunity_properties , # type: ignore
143147 ],
148+ responses = {
149+ 201 : {
150+ "model" : OpportunitySearchRecord ,
151+ "content" : {TYPE_JSON : {}},
152+ }
153+ },
144154 summary = "Search Opportunities for the product" ,
145155 tags = ["Products" ],
146156 )
147157
148158 if root_router .supports_async_opportunity_search :
149- self .add_api_route (
150- path = "/opportunities" ,
151- endpoint = self .search_opportunities_async ,
152- name = f"{ self .root_router .name } :{ self .product .id } :search-opportunities" ,
153- methods = ["POST" ],
154- status_code = status .HTTP_201_CREATED ,
155- summary = "Search Opportunities for the product" ,
156- tags = ["Products" ],
157- )
158-
159159 self .add_api_route (
160160 path = "/opportunities/{opportunity_collection_id}" ,
161161 endpoint = self .get_opportunity_collection ,
@@ -216,18 +216,19 @@ def get_product(self: Self, request: Request) -> Product:
216216 ],
217217 )
218218
219- async def search_opportunities (
219+ async def search_opportunities ( # noqa: C901
220220 self : Self ,
221221 search : OpportunityRequest ,
222222 request : Request ,
223- response : GeoJSONResponse ,
224- prefer : str | None = Depends (get_preference ),
223+ response : Response ,
225224 next : Annotated [str | None , Body ()] = None ,
226225 limit : Annotated [int , Body ()] = 10 ,
227- ) -> OpportunityCollection :
226+ prefer : str | None = Depends (get_preference ),
227+ ) -> OpportunityCollection | Response :
228228 """
229229 Explore the opportunities available for a particular set of constraints
230230 """
231+ # synchronous opportunities search
231232 if (
232233 not self .root_router .supports_async_opportunity_search
233234 or prefer is Prefer .wait
@@ -272,20 +273,7 @@ async def search_opportunities(
272273
273274 return OpportunityCollection (features = features , links = links )
274275
275- raise AssertionError ("Expected code to be unreachable" )
276-
277- async def search_opportunities_async (
278- self : Self ,
279- search : OpportunityRequest ,
280- request : Request ,
281- response : Response ,
282- prefer : str | None = Depends (get_preference ),
283- ) -> OpportunitySearchRecord :
284- """
285- Initiate an asynchronous search for opportunities.
286-
287- TODO: Do I need a location header somewhere?
288- """
276+ # asynchronous opportunities search
289277 if (
290278 prefer is None
291279 or prefer is Prefer .respond_async
@@ -296,14 +284,19 @@ async def search_opportunities_async(
296284 self .root_router .add_opportunity_search_record_self_link (
297285 search_record , request
298286 )
299- response .headers ["Location" ] = str (
287+ headers = {}
288+ headers ["Location" ] = str (
300289 self .root_router .generate_opportunity_search_record_href (
301290 request , search_record .id
302291 )
303292 )
304293 if prefer is not None :
305- response .headers ["Preference-Applied" ] = "respond-async"
306- return search_record
294+ headers ["Preference-Applied" ] = "respond-async"
295+ return JSONResponse (
296+ status_code = 201 ,
297+ content = search_record .model_dump (mode = "json" ),
298+ headers = headers ,
299+ )
307300 case Failure (e ) if isinstance (e , ConstraintsException ):
308301 raise e
309302 case Failure (e ):
@@ -315,8 +308,8 @@ async def search_opportunities_async(
315308 status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
316309 detail = "Error initiating an asynchronous opportunity search" ,
317310 )
318- case x :
319- raise AssertionError (f"Expected code to be unreachable: { x } " )
311+ case y :
312+ raise AssertionError (f"Expected code to be unreachable: { y } " )
320313
321314 raise AssertionError ("Expected code to be unreachable" )
322315
0 commit comments