Four levels of granularity
Each level overrides the one before it. First non-None wins.
Per-location parameters
Cases are specified per HTTP location, not one-for-all:body_case— JSON request body keys (default"camel")query_case— URL query string keys (default"snake")path_case— URL path parameter keys (default"snake")
Supported cases
Examples
Clean API (most common) — factory level only
camel_api_factory.py
API with snake_case everywhere
snake_api_factory.py
Mixed API — one endpoint differs
per_endpoint_case.py
Schema-level override (nested model)
schema_case.py
Field-level override (single field)
field_case.py
Resolution at serialization time
__case__
names the keys of the model that declares it — so both are read from whichever
model owns the object being serialised. A nested EventDateTime gets its own
__case__; the Case("pascal") on one of its fields is honoured there exactly
as it would be at the top.
What does not inherit is __case__ itself: it says “all keys in that
model”, so a model below one that declares it falls back to the endpoint or
factory default rather than to its parent’s override. Keys with no model behind
them at all — what a Format transform produced, the contents of a free-form
Dict[str, Any] — take the endpoint default too, because there is no
declaration to read.
One exception: path parameters
A path key is not a key on the wire, it is the name of a hole in the endpoint’surl_template. Only WireName and path_case apply to it. A model’s
__case__ does not, since renaming doc_id to DocId would leave {doc_id}
with nothing to fill it — a broken template rather than a wire mismatch.
When no convention is right
The cascade converts a whole word at a time, and an acronym inside a field name is where that goes wrong.snake_to_camel capitalises each component, so
i_cal_uid becomes iCalUid — and Google Calendar documents iCalUID. The same
shape gives htmlUrl for htmlURL and ipAddress for IPAddress. No entry in
the cascade produces those, because they are not a convention.
WireName names the key outright, and wins over
every level above:
eventId and fileUrl are camelCase in Google’s own docs — so
check rather than guess.
This failure is silent, which is why it is worth a marker. Many APIs ignore a
query parameter they do not recognise, so the misspelled filter is dropped, the
unfiltered result comes back, and the call answers 200. Charter’s own Calendar
pack sent iCalUid for as long as it existed. Assert the parameter names on the
wire against a respx route; reading the schema is what misses it.
Related
WireName— the key the API documents, verbatimCase— the field-level markerKeyCase— the type the*_casesettings accept- Casing and encoding — the resolved settings on a built
Tool - The builder — the
*_case_overrideparameters