WSDL folder-drop
Point XTR at a folder of WSDL files. Every wsdl:operation becomes
a live POST /group/operation endpoint on next boot.
SOAP lane only. WSDL-driven generation produces SOAP DSLs
(envelope + Handlebars). REST DSLs (kind: rest) are hand-written
— see REST passthrough.
Enable
# xtr.yaml
wsdl_watch_dir: ./wsdl
Absent = feature off (only hand-written DSLs load).
Layout
wsdl/
├── <owner>/ # URL prefix — often the org / vendor slug
│ └── <subsystem>/ # organisational grouping (optional)
│ ├── N.wsdl
│ └── N.meta.yaml # sidecar: X-Road identity for the envelope
└── <single-service>/ # flat: no subsystem subdir
├── api.wsdl
└── api.meta.yaml
Path mapping:
| WSDL location | Generated DSL | URL |
|---|---|---|
wsdl/foo/api.wsdl | DSL/foo/<op>.yml | POST /foo/<op> |
wsdl/foo/bar/N.wsdl | DSL/foo/bar-<op>.yml | POST /foo/bar-<op> |
Nesting is for human browsability. URL segments are always
/<owner>/<optionally-prefixed-op> — 2 segments, no exceptions.
Sidecar meta.yaml
Placed next to each WSDL (api.wsdl + api.meta.yaml).
member_class: GOV
member_code: "70000123"
subsystem_code: my-service
# Optional: explicit service code (defaults to operation name).
service_code: someMethod
# Optional: public-HTTPS override for dual-mode vendors like
# Ariregister. When set, DSLs skip X-Road envelope wrapping and
# hit this URL directly. Vendor auth (username/password in SOAP
# body) still required.
service_url: https://vendor.example.com/soap
When service_url: is set → plain SOAP envelope, direct HTTPS.
Otherwise → X-Road-wrapped envelope, routed via security_server:.
Marker header + collision rules
Every generated DSL starts with:
# GENERATED BY XTR from WSDL — do not edit; delete this line to convert into a hand-written override
Collision rules on the next boot:
| Existing file | Action |
|---|---|
| Doesn't exist | Write |
| Has marker | Overwrite |
| No marker (hand-written) | SKIP with WARN — your edits stand |
Delete the marker line from a generated file to convert it into a hand-written override that survives regeneration.
Deterministic output
Same WSDL always produces byte-equal DSL YAML. git diff between
two boots is empty. Any drift = real WSDL change (or a generator
bug — file it).
Harvest more Estonian services
RIA publishes a public catalog at https://x-tee.ee/catalogue-data/EE/index.json
listing every X-Road subsystem's WSDLs. The shipped
scripts/harvest-xtee-wsdls.sh fetches on demand:
./scripts/harvest-xtee-wsdls.sh --member 70008440 # RR (Rahvastikuregister)
./scripts/harvest-xtee-wsdls.sh --subsystem liiklusregister
./scripts/harvest-xtee-wsdls.sh # everything (~421 subsystems)
Auto-writes .meta.yaml sidecars from catalog metadata. Groups
under wsdl/<owner>/ per the script's built-in OWNERS map (extend
the map for new memberCodes).
Scale limits
The current DSL loader validates every Handlebars template at boot. Practical caps:
| Subsystems | Endpoints | Boot |
|---|---|---|
| Ariregister only | 33 | ~1 s |
| Climate orbit (shipped default) | 194 | ~1 s |
| ~20 subsystems | ~500–800 | ~10 s |
| Full RIA catalog (~421) | ~3000+ | not viable today (task 014) |
Use --subsystem / --member filters to keep the working set
manageable.
Unsupported constructs
WSDL parser bails (with WARN, skips the operation, XTR still boots)
on: xsd:choice, WSDL 2.0, RPC/encoded style, MIME attachments,
xsd:import beyond framework schemas. Override with a hand-written
DSL for those cases (see Getting started).
Why no admin HTTP endpoint
There's no POST /admin/wsdl-from-url. Ingestion is folder-only
by design — admin and consumer surfaces stay hard-separated at
the infrastructure layer, not muddled together via in-process auth.
For URL-driven ingestion, curl -o wsdl/foo/api.wsdl <url> from
your config-management job.