HTTP behaviour¶
URL grammar¶
Every route follows SDMX-REST 2.2.2. The grammar decides what a key means:
2.2.2 makes the time dimension a key slot, so a key has one dot-separated
segment per key dimension, time included. On a data structure with
dimensions FREQ, REF_AREA and TIME_PERIOD, the key A.CA. has three
segments, and A.CA is a 400 that names the dimensions. all matches every
key.
SDMX-REST 1.5 and 2.1 keep time out of the key, so their keys are one segment shorter for the same structure. Read against the 2.2.2 slots, a 1.5 key shifts every value one dimension and returns a wrong answer without an error. A consumer that serves the older grammar runs a forwarder that translates each request before it reaches these routes.
The routes accept two 1.5 spellings: the all key, and startPeriod and
endPeriod. The availability path without a componentID is not routed; a
forwarder that serves it maps it to componentID=all.
/availability needs an explicit version, such as 1.0; latest is a 422.
Formats¶
Accept chooses the format. Structure routes write:
| Format | Media type |
|---|---|
| SDMX-JSON 2.0 | application/vnd.sdmx.structure+json;version=2.0 |
| SDMX-ML 3.0 | application/vnd.sdmx.structure+xml;version=3.0 |
| SDMX-ML 2.1 | application/vnd.sdmx.structure+xml;version=2.1 |
An Accept that excludes every format a route writes gets a 406. Common
shorthand, such as application/json or a media type without a version,
matches. Responses advertise the two-part version (version=2.0) that
SDMX-REST 2.2.2 publishes; requests may send either form.
A structure or metadata query that matches nothing answers 204 for SDMX-JSON;
XML responses keep their own empty form and answer 200. An /availability
query that matches nothing answers 204 in every format.
Languages¶
SDMX-JSON carries both name, in one language, and names, in every
language. The service sets name and description to the best match for
Accept-Language, and answers with Content-Language. ?lang=fr overrides
the header, for clients that cannot set one; the service treats it as
Accept-Language: fr everywhere, including the ETag.
Conditional GET¶
Successful responses carry ETag, Last-Modified and Cache-Control
(RestSettings.cache_control). The ETag hashes the app version, the
effective_token, the path, the query string, Accept and the resolved
language. It does not read the body, so it is computed before the route runs
and is the same with or without compression.
If-None-Match and If-Modified-Since answer 304 when they match. A new
edition has a new token, and an annotation change a new fingerprint
(Annotations and overlays); either changes every ETag.
Error responses carry no ETag and no Cache-Control.
Other behaviour¶
- Unknown query parameters are a 400 that names the parameter, so a typo
such as
?detial=fullfails instead of being ignored. asOfis a 501 on the structure and metadata routes. The service serves one edition and keeps no history./availabilitydoes not takeasOf, so there it is the unknown-parameter 400.HEADworks on everyGETroute and returns theGETheaders.- Compression: gzip through isa-l, at level 1, for responses of 1 KB or more. Parquet, zstd, zip and octet-stream bodies pass uncompressed, as do the types Starlette never compresses, such as images and event streams.
- Content no format can carry is a 500 that lists each artefact and the sdmxlib rule it breaks, for example a component with no concept.
- CORS answers every preflight, including for paths the app does not
route. It allows
GET,HEAD,OPTIONSandPOST.
Middleware order¶
create_app installs the middleware in a fixed order. From the outside in:
- CORS, outermost, so a preflight to any path gets an answer. A preflight that reached the router would get a 404, which the browser reports as a CORS failure.
outer_middleware, the consumer's, which sees the client's request and the encoded response.- Performance log, outside gzip and HEAD, so it counts the bytes sent
and records the client's method. CORS and
outer_middlewaresit outside it, so its time leaves them out. - HEAD, which turns
HEADintoGETfor the layers inside it, inside the logging taps so they record the client's method. - gzip. It compares only the base media type, and the rewrite changes
only the
versionparameter, so its place beside the rewrite changes no response; the test pins it here. - Media-type version rewrite.
?lang=, outside the conditional-GET layer, so?lang=frhashes likeAccept-Language: fr.- Conditional GET, innermost.
tests/test_library_create_app.py asserts this order.