Skip to content

Commit 876eff6

Browse files
committed
fix(client-sdks): ensure data field ordering for list response iteration
The model template emits __iter__/__getitem__/__len__ methods only for the first array field in a model. Several list response schemas had non-array fields (like object) before the data field, causing the template to skip iteration methods. This made iterating a response yield (field_name, value) tuples instead of data items. Add reorder_data_field_first() in build_hierarchy.py to ensure the data property comes first in any schema with an array data field. Also update uv.lock to ogx-open-client 1.0.3.dev4. Signed-off-by: E Geiger <egeiger@redhat.com>
1 parent 081b2a1 commit 876eff6

2 files changed

Lines changed: 48 additions & 3 deletions

File tree

client-sdks/openapi/build_hierarchy.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,47 @@ def mark_unwrappable_list_responses(spec: dict[str, Any]) -> int:
162162
return count
163163

164164

165+
def reorder_data_field_first(spec: dict[str, Any]) -> int:
166+
"""Ensure 'data' is the first property in list/page response schemas.
167+
168+
The model_generic.mustache template emits __iter__/__getitem__/__len__ methods
169+
only for the first array field in a model (using the {{#-first}} guard). If a
170+
non-array field like 'object' comes before 'data', the iteration methods are
171+
skipped, making the model non-iterable and breaking code that does
172+
`for item in response`.
173+
174+
Returns the number of schemas reordered.
175+
"""
176+
schemas = spec.get("components", {}).get("schemas", {})
177+
count = 0
178+
179+
for schema_def in schemas.values():
180+
if not isinstance(schema_def, dict):
181+
continue
182+
props = schema_def.get("properties")
183+
if not isinstance(props, dict) or "data" not in props:
184+
continue
185+
data_prop = props.get("data", {})
186+
if not isinstance(data_prop, dict):
187+
continue
188+
# Only reorder if data is an array type and not already first
189+
is_array = data_prop.get("type") == "array" or "items" in data_prop
190+
if not is_array:
191+
continue
192+
keys = list(props.keys())
193+
if keys[0] == "data":
194+
continue
195+
# Reorder: data first, then everything else in original order
196+
reordered = {"data": props["data"]}
197+
for key in keys:
198+
if key != "data":
199+
reordered[key] = props[key]
200+
schema_def["properties"] = reordered
201+
count += 1
202+
203+
return count
204+
205+
165206
def mark_streaming_operations(spec: dict[str, Any]) -> int:
166207
"""Add x-streaming vendor extensions for operations with text/event-stream responses.
167208
@@ -338,6 +379,10 @@ def process_openapi(input_file: str, output_file: str, hierarchy_file: str) -> N
338379
if streaming:
339380
print(f" Marked {streaming} endpoints with streaming type metadata")
340381

382+
reordered = reorder_data_field_first(spec)
383+
if reordered:
384+
print(f" Reordered 'data' to first property in {reordered} schemas")
385+
341386
# --- Write output ---
342387
with open(output_file, "w") as f:
343388
yaml_handler.dump(spec, f)

uv.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)