oatpp 1.3 emits `"required": []` on schemas with no required fields. OpenAPI 3.0.x rejects this with "must NOT have fewer than 1 items", which silently breaks strict consumers. Orval's typed fetch client swallowed it (the violation surfaces only as a non-fatal warning), but Orval's Zod generator (added downstream in fewo-webapp's #469 increment 2) fails hard: must NOT have fewer than 1 items at /components/schemas/<DTO>/required must have required property '$ref' at /components/schemas/<DTO> must match exactly one schema in oneOf at /components/schemas/<DTO> 83 of fewo-webapp's 198 DTOs trip this. Stripping the empty array (absence of the keyword has the same semantics) is the spec-compliant fix. Bumps to v0.4.1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
59 lines
2.2 KiB
Python
Executable file
59 lines
2.2 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""Post-process openapi.json before handing it to Orval.
|
|
|
|
oatpp 1.3's Swagger generator produces a valid spec but with rough edges
|
|
that make the generated client less ergonomic:
|
|
|
|
- Missing operationIds on some endpoints → orval falls back to path-based
|
|
names that collide. We synthesise an operationId from method + path.
|
|
- summary/description strings occasionally contain stray control characters.
|
|
- Some endpoints have no tags, which throws off orval's file-splitting.
|
|
|
|
Run between `fetch-openapi.sh` and `orval` (see package.json `codegen`).
|
|
"""
|
|
import json
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
SRC = Path("openapi.json")
|
|
if not SRC.exists():
|
|
sys.exit(f"{SRC} not found — run fetch-openapi.sh first")
|
|
|
|
spec = json.loads(SRC.read_text())
|
|
|
|
|
|
def op_id(method: str, path: str) -> str:
|
|
"""`getApiAnnouncementsEntityIdHistory` from `GET /api/announcements/{entity_id}/history`."""
|
|
parts = [method.lower()]
|
|
for seg in path.strip("/").split("/"):
|
|
if seg.startswith("{") and seg.endswith("}"):
|
|
parts.append(seg[1:-1])
|
|
else:
|
|
parts.append(seg)
|
|
return re.sub(r"[^A-Za-z0-9]+(\w)", lambda m: m.group(1).upper(),
|
|
"_".join(parts))
|
|
|
|
|
|
paths = spec.get("paths", {})
|
|
for path, methods in paths.items():
|
|
for method, op in methods.items():
|
|
if not isinstance(op, dict):
|
|
continue
|
|
op.setdefault("operationId", op_id(method, path))
|
|
op.setdefault("tags", [path.strip("/").split("/")[1] if "/" in path.strip("/") else "default"])
|
|
|
|
# oatpp 1.3 emits `"required": []` on schemas that have no required fields.
|
|
# OpenAPI 3.0.x rejects this (`must NOT have fewer than 1 items`), which
|
|
# breaks strict consumers like Orval's Zod generator. Strip empty arrays —
|
|
# absence of the keyword has the same semantics.
|
|
schemas = spec.get("components", {}).get("schemas", {})
|
|
stripped = 0
|
|
for sch in schemas.values():
|
|
if isinstance(sch, dict) and sch.get("required") == []:
|
|
del sch["required"]
|
|
stripped += 1
|
|
|
|
SRC.write_text(json.dumps(spec, indent=2))
|
|
print(f" postprocessed {SRC} — {len(paths)} paths"
|
|
+ (f", stripped empty `required` from {stripped} schemas" if stripped else ""))
|