Skip to main content
All schema fields are written snake_case. Charter converts keys to the API’s expected casing at serialization time — request only. Responses are never case-converted, and values are never touched, only keys.

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")
This matters more often than it sounds: Google APIs typically want camelCase bodies but snake_case query parameters.

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

Field-level and schema-level overrides apply at the top level of the body. Nested objects recurse with the endpoint/factory default, because a field marker names a field on that schema — it would be meaningless keyed against a nested object’s field names.

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:
Reach for it only where the API’s reference actually spells an acronym in full. Most do not — 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.