swax/openapi
Parsing of OpenAPI/Swagger specifications and extraction of paths and schemas for the traceability graph, plus structural diffing of two dereferenced specs and classification of endpoint/schema changes.
The graph operates on paths only — no HTTP methods, no resource abstraction
(architectural rule: minimal abstraction). Swagger 2.0 and OpenAPI 3.x are
handled transparently — both store paths under paths. The diff sees
methods/parameters/schemas for analysis only — classified changes surface as
paths with descriptions, never as method/schema-level entries.
Parsing & extraction
parse_spec(spec_path: pathlib.Path) -> spec: dict
Parses a specification file into a fully dereferenced dict (all non-cyclic
$ref inlined).
spec_path: path to a.yaml/.yml/.jsonspec file.spec: dereferenced specification containing paths and schemas.
Algorithm:
- Read the file and parse it via Prance's formats helper.
- Construct a Prance reference resolver over the parsed spec (strict mode off, resolve all reference types).
- Configure the resolver to terminate reference cycles by emitting a
$refmarker instead of raising — prevents failure on self-referential and mutually-recursive schemas. - Return the dereferenced specification.
- On any parser failure, raise
SpecParseErrorwith the path and original reason.
Requirements:
- Non-cyclic
$refis resolved in memory — downstream code never resolves those references manually. - Cyclic
$refterminates at the cycle point with a$refmarker preserving structural information.
Constraints:
- RAM usage scales with spec size and reference count (known limitation, accepted).
- The Prance post-resolve spec validator is intentionally bypassed — it rejects otherwise valid recursive schemas after dereferencing.
extract_paths(spec: dict) -> paths: list[str]
Collects API path templates from a parsed specification, discarding HTTP methods.
spec: dereferenced dict (output ofparse_spec).paths: sorted list of path templates (e.g./users,/users/{id}).
Algorithm:
- Read the
pathsmapping fromspec. - Return its keys as a sorted list.
Requirements:
- Result feeds the traceability graph nodes directly — no method-level entries.
extract_schemas(spec: dict) -> schemas: dict
Collects schema definitions from a parsed specification for LLM context enrichment.
spec: dereferenced dict.schemas: mapping of schema name to its definition (already inlined by the parser).
Algorithm:
- If
specexposes OpenAPI 3.xcomponents, return its schemas sub-mapping. - Otherwise return the Swagger 2.0
definitionssub-mapping.
Requirements:
- Transparently distinguishes OpenAPI 3.x (
components.schemas) from Swagger 2.0 (definitions). - Schemas are used only by
build_refine_user_prompt— never stored in the graph.
discover_specs(root: pathlib.Path) -> specs: list[pathlib.Path]
Enumerates spec files under root by extension and a lightweight content
heuristic.
root: directory to search (typically the local specs path fromSpecsConfig).specs: sorted list of spec file paths.
Algorithm:
- Walk
rootrecursively. - Keep files with extension
.yaml/.yml/.json. - Keep files whose head contains an
openapiorswaggerkey.
Requirements:
- The heuristic is cheap — full parsing happens later via
parse_spec. - Returned order is deterministic (sorted).
Diffing & classification
diff_specs(base: dict, current: dict) -> diff: DeepDiff
Computes a structural diff between two dereferenced specifications.
base: baseline (local) spec dict — output ofparse_spec.current: fresh (cloned repo) spec dict — output ofparse_spec.diff: aDeepDiffresult consumed byclassify_endpoint_changes.
Algorithm:
- Build a
DeepDiffoverbaseandcurrentwithignore_orderand the cutoff option fromdeepdiff. - Return the result unchanged — classification happens in
classify_endpoint_changes.
Requirements:
- Both inputs are fully dereferenced (Prance already inlined
$refviaparse_spec). - List order is ignored — endpoint order is not significant.
Constraints:
- Do not classify changes here — this routine only computes the raw structural diff.
- Avoid
verbose_level=2in the production path.
classify_endpoint_changes(diff: DeepDiff) -> changes: EndpointDiff
Classifies a raw structural diff into endpoint-level changes.
diff:DeepDiffresult fromdiff_specs.changes: anEndpointDiffaggregating added, removed, and modified endpoints with schema detail.
Algorithm:
- Walk the diff change sets (
dictionary_item_added,dictionary_item_removed,values_changed) by their path strings. These are the deepdiff categories produced bydiff_specs. - Paths under the
pathskey become endpoint changes: added / removed / modified. - Paths under the
components/definitionskeys are schema changes — because$refis already dereferenced, each affected endpoint surfaces the change directly; attribute it to that endpoint. - Aggregate multiple changes on the same path into a single
modifiedentry with a list of descriptions. - Return the
EndpointDiff.
Requirements:
- Swagger 2.0 (
definitions) and OpenAPI 3.x (components.schemas) handled transparently. - Modified entries carry human-readable change descriptions for the Impact Report.
Constraints:
- Do not emit method-level or schema-level entries as separate paths — paths only.
- Do not introduce endpoints outside the union of base and current path keys.
EndpointDiff(added, removed, modified)
Classified change result between baseline and current specifications.
| Property | Type | Description |
|---|---|---|
added |
list[str] |
Endpoint paths present in the current spec but not in the baseline. |
removed |
list[str] |
Endpoint paths present in the baseline but not in the current spec. |
modified |
dict[str, list[str]] |
Endpoint path → list of human-readable change descriptions. |
Methods:
| Method | Return | Description |
|---|---|---|
has_changes() |
bool |
True when any endpoint was added, removed, or modified. |
changed_paths() |
list[str] |
Union of added, removed, and modified endpoint paths — sorted and deduplicated. Deterministic; each path appears once. |
Errors
| Exception | Cause |
|---|---|
SpecParseError(path: pathlib.Path, reason: str) |
Raised by parse_spec when parsing or dereferencing a specification fails. Carries the offending spec file path and the original Prance error message. |
See also
- Traceability graph — what
extract_pathsfeeds. - Impact Report — what
EndpointDifffeeds. - Architecture / applications/plan cell — consumes the diff API.