@@ -417,9 +417,11 @@ def _construct_api_requests(
417417 """
418418 Constructs an HTTP request object for the specified water data API service.
419419
420- Depending on the input parameters (whether there's lists of multiple
421- argument values), the function determines whether to use a GET or POST
422- request, formats parameters appropriately, and sets required headers.
420+ For most services, list parameters are comma-joined and sent as a single
421+ GET request (e.g. ``parameter_code=["00060","00010"]`` becomes
422+ ``parameter_code=00060,00010`` in the URL). For services that do not
423+ support comma-separated values (currently only ``monitoring-locations``),
424+ a POST request with CQL2 JSON is used instead.
423425
424426 Parameters
425427 ----------
@@ -445,36 +447,41 @@ def _construct_api_requests(
445447 Notes
446448 -----
447449 - Date/time parameters are automatically formatted to ISO8601.
448- - If multiple values are provided for non-single parameters, a POST request
449- is constructed.
450- - The function sets appropriate headers for GET and POST requests.
451450 """
452451 service_url = f"{ OGC_API_URL } /collections/{ service } /items"
453452
454- # Identify which parameters should be included in the POST content body
455- post_params = {
456- k : v
457- for k , v in kwargs .items ()
458- if k not in _DATE_RANGE_PARAMS and isinstance (v , (list , tuple )) and len (v ) > 1
459- }
460-
461- # Everything else goes into the params dictionary for the URL
462- params = {k : v for k , v in kwargs .items () if k not in post_params }
463- # Set skipGeometry parameter (API expects camelCase)
464- params ["skipGeometry" ] = skip_geometry
453+ # The monitoring-locations endpoint does not support comma-separated values
454+ # for multi-value GET parameters; CQL2 POST is required for that service.
455+ _cql2_required_services = {"monitoring-locations" }
465456
466- # If limit is none or greater than 50000, then set limit to max results. Otherwise,
467- # use the limit
468- params ["limit" ] = 50000 if limit is None or limit > 50000 else limit
457+ # Format date/time parameters to ISO8601 first — both routing paths need it.
458+ for key in _DATE_RANGE_PARAMS :
459+ if key in kwargs :
460+ kwargs [key ] = _format_api_dates (
461+ kwargs [key ],
462+ date = (service == "daily" and key != "last_modified" ),
463+ )
469464
470- # Indicate if function needs to perform POST conversion
471- POST = bool (post_params )
465+ if service in _cql2_required_services :
466+ # Legacy path: POST with CQL2 for multi-value params
467+ post_params = {
468+ k : v
469+ for k , v in kwargs .items ()
470+ if k not in _DATE_RANGE_PARAMS
471+ and isinstance (v , (list , tuple ))
472+ and len (v ) > 1
473+ }
474+ params = {k : v for k , v in kwargs .items () if k not in post_params }
475+ else :
476+ # Join list/tuple values with commas for multi-value GET parameters.
477+ post_params = {}
478+ params = {
479+ k : "," .join (str (x ) for x in v ) if isinstance (v , (list , tuple )) else v
480+ for k , v in kwargs .items ()
481+ }
472482
473- # Convert dates to ISO08601 format
474- for i in _DATE_RANGE_PARAMS :
475- if i in params :
476- dates = service == "daily" and i != "last_modified"
477- params [i ] = _format_api_dates (params [i ], date = dates )
483+ params ["skipGeometry" ] = skip_geometry
484+ params ["limit" ] = 50000 if limit is None or limit > 50000 else limit
478485
479486 # `len()` instead of truthiness: a numpy ndarray would raise on `if bbox:`.
480487 if bbox is not None and len (bbox ) > 0 :
@@ -490,7 +497,7 @@ def _construct_api_requests(
490497
491498 headers = _default_headers ()
492499
493- if POST :
500+ if post_params :
494501 headers ["Content-Type" ] = "application/query-cql-json"
495502 request = requests .Request (
496503 method = "POST" ,
0 commit comments