serde(rename) for camelCase API Fields

Map JavaScript-style camelCase JSON keys onto Rust snake_case fields with #[serde(rename = ...)] or rename_all.

Patterns

Detailed Explanation

Bridging camelCase JSON and snake_case Rust

Most JavaScript and Java backends emit camelCase JSON keys (firstName, createdAt). Rust's style guide demands snake_case (first_name, created_at). serde lets you have both.

Example JSON

{
  "firstName": "Ada",
  "lastName": "Lovelace",
  "createdAt": "2024-01-15T10:00:00Z"
}

Per-field rename (auto-generated)

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
    #[serde(rename = "firstName")]
    pub first_name: String,
    #[serde(rename = "lastName")]
    pub last_name: String,
    #[serde(rename = "createdAt")]
    pub created_at: String,
}

Container-level rename

If every field follows the same convention, replace the per-field attributes with a single container-level rename_all:

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Root {
    pub first_name: String,
    pub last_name: String,
    pub created_at: String,
}

This is shorter, harder to forget, and produces identical wire output.

Available rename_all values

"lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE", "kebab-case", "SCREAMING-KEBAB-CASE".

Mixed casing

If only a few fields are exceptions, combine container-level rename_all with per-field rename for the outliers:

#[serde(rename_all = "camelCase")]
pub struct Root {
    pub first_name: String,
    pub last_name: String,
    #[serde(rename = "URL")]
    pub url: String,
}

Why the rename matters

Without these attributes, deserialization fails with missing field "first_name" — the JSON key is firstName and serde looks for an exact match. Renames give you a clean Rust API while staying compatible with whatever wire format the upstream service uses.

Use Case

Almost every TypeScript-, Java-, or Kotlin-based backend emits camelCase JSON. Rust clients consuming those APIs need rename_all to keep idiomatic snake_case fields without breaking the wire contract.

Try It — JSON to Rust Struct Converter

Open full tool