Jeremiah Lowin commited on
Commit
71ef915
·
1 Parent(s): 4a8c120

Refactor array parameter formatting to reduce code duplication

Browse files

Extract common array formatting logic into format_array_parameter utility function.
Addresses automated review feedback about code duplication between path and query parameter handling.

src/fastmcp/server/openapi.py CHANGED
@@ -27,6 +27,7 @@ from fastmcp.utilities.logging import get_logger
27
  from fastmcp.utilities.openapi import (
28
  HTTPRoute,
29
  _combine_schemas,
 
30
  format_description_with_responses,
31
  )
32
 
@@ -296,46 +297,10 @@ class OpenAPITool(Tool):
296
  if is_array:
297
  # Format array values as comma-separated string
298
  # This follows the OpenAPI 'simple' style (default for path)
299
- if all(
300
- isinstance(item, str | int | float | bool)
301
- for item in param_value
302
- ):
303
- # Handle simple array types
304
- path = path.replace(
305
- f"{{{param_name}}}", ",".join(str(v) for v in param_value)
306
- )
307
- else:
308
- # Handle complex array types (containing objects/dicts)
309
- try:
310
- # Try to create a simple representation without Python syntax artifacts
311
- formatted_parts = []
312
- for item in param_value:
313
- if isinstance(item, dict):
314
- # For objects, serialize key-value pairs
315
- item_parts = []
316
- for k, v in item.items():
317
- item_parts.append(f"{k}:{v}")
318
- formatted_parts.append(".".join(item_parts))
319
- else:
320
- # Fallback for other complex types
321
- formatted_parts.append(str(item))
322
-
323
- # Join parts with commas
324
- formatted_value = ",".join(formatted_parts)
325
- path = path.replace(f"{{{param_name}}}", formatted_value)
326
- except Exception as e:
327
- logger.warning(
328
- f"Failed to format complex array path parameter '{param_name}': {e}"
329
- )
330
- # Fallback to string representation, but remove Python syntax artifacts
331
- str_value = (
332
- str(param_value)
333
- .replace("[", "")
334
- .replace("]", "")
335
- .replace("'", "")
336
- .replace('"', "")
337
- )
338
- path = path.replace(f"{{{param_name}}}", str_value)
339
  continue
340
 
341
  # Default handling for non-array parameters or non-array schemas
@@ -365,34 +330,11 @@ class OpenAPITool(Tool):
365
  # as multiple parameters with the same name
366
  query_params[p.name] = param_value
367
  else:
368
- # For arrays of simple types (strings, numbers, etc.), join with commas
369
- if all(
370
- isinstance(item, str | int | float | bool)
371
- for item in param_value
372
- ):
373
- query_params[p.name] = ",".join(str(v) for v in param_value)
374
- else:
375
- # For complex types, try to create a simpler representation
376
- try:
377
- # Try to create a simple string representation
378
- formatted_parts = []
379
- for item in param_value:
380
- if isinstance(item, dict):
381
- # For objects, serialize key-value pairs
382
- item_parts = []
383
- for k, v in item.items():
384
- item_parts.append(f"{k}:{v}")
385
- formatted_parts.append(".".join(item_parts))
386
- else:
387
- formatted_parts.append(str(item))
388
-
389
- query_params[p.name] = ",".join(formatted_parts)
390
- except Exception as e:
391
- logger.warning(
392
- f"Failed to format complex array query parameter '{p.name}': {e}"
393
- )
394
- # Fallback to string representation
395
- query_params[p.name] = param_value
396
  else:
397
  # Non-array parameters are passed as is
398
  query_params[p.name] = param_value
 
27
  from fastmcp.utilities.openapi import (
28
  HTTPRoute,
29
  _combine_schemas,
30
+ format_array_parameter,
31
  format_description_with_responses,
32
  )
33
 
 
297
  if is_array:
298
  # Format array values as comma-separated string
299
  # This follows the OpenAPI 'simple' style (default for path)
300
+ formatted_value = format_array_parameter(
301
+ param_value, param_name, is_query_parameter=False
302
+ )
303
+ path = path.replace(f"{{{param_name}}}", str(formatted_value))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
  continue
305
 
306
  # Default handling for non-array parameters or non-array schemas
 
330
  # as multiple parameters with the same name
331
  query_params[p.name] = param_value
332
  else:
333
+ # Format array as comma-separated string when explode=False
334
+ formatted_value = format_array_parameter(
335
+ param_value, p.name, is_query_parameter=True
336
+ )
337
+ query_params[p.name] = formatted_value
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
338
  else:
339
  # Non-array parameters are passed as is
340
  query_params[p.name] = param_value
src/fastmcp/utilities/openapi.py CHANGED
@@ -39,6 +39,60 @@ ParameterLocation = Literal["path", "query", "header", "cookie"]
39
  JsonSchema = dict[str, Any]
40
 
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  class ParameterInfo(FastMCPBaseModel):
43
  """Represents a single parameter for an HTTP operation in our IR."""
44
 
 
39
  JsonSchema = dict[str, Any]
40
 
41
 
42
+ def format_array_parameter(
43
+ values: list, parameter_name: str, is_query_parameter: bool = False
44
+ ) -> str | list:
45
+ """
46
+ Format an array parameter according to OpenAPI specifications.
47
+
48
+ Args:
49
+ values: List of values to format
50
+ parameter_name: Name of the parameter (for error messages)
51
+ is_query_parameter: If True, can return list for explode=True behavior
52
+
53
+ Returns:
54
+ String (comma-separated) or list (for query params with explode=True)
55
+ """
56
+ # For arrays of simple types (strings, numbers, etc.), join with commas
57
+ if all(isinstance(item, str | int | float | bool) for item in values):
58
+ return ",".join(str(v) for v in values)
59
+
60
+ # For complex types, try to create a simpler representation
61
+ try:
62
+ # Try to create a simple string representation
63
+ formatted_parts = []
64
+ for item in values:
65
+ if isinstance(item, dict):
66
+ # For objects, serialize key-value pairs
67
+ item_parts = []
68
+ for k, v in item.items():
69
+ item_parts.append(f"{k}:{v}")
70
+ formatted_parts.append(".".join(item_parts))
71
+ else:
72
+ formatted_parts.append(str(item))
73
+
74
+ return ",".join(formatted_parts)
75
+ except Exception as e:
76
+ param_type = "query" if is_query_parameter else "path"
77
+ logger.warning(
78
+ f"Failed to format complex array {param_type} parameter '{parameter_name}': {e}"
79
+ )
80
+
81
+ if is_query_parameter:
82
+ # For query parameters, fallback to original list
83
+ return values
84
+ else:
85
+ # For path parameters, fallback to string representation without Python syntax
86
+ str_value = (
87
+ str(values)
88
+ .replace("[", "")
89
+ .replace("]", "")
90
+ .replace("'", "")
91
+ .replace('"', "")
92
+ )
93
+ return str_value
94
+
95
+
96
  class ParameterInfo(FastMCPBaseModel):
97
  """Represents a single parameter for an HTTP operation in our IR."""
98