JSON List to struct using Serde

I have an API response which looks like this:

{
    "resource": "payment",
    "id": "tr_WDqYK6vllg",
    "mode": "test",
    "createdAt": "2018-03-20T13:13:37+00:00",
    "amount": {
        "value": "10.00",
        "currency": "EUR"
    },
    "description": "Order #12345",
    "method": null,
    "metadata": {
        "order_id": "12345"
    },
    "status": "open",
    "isCancelable": false,
    "locale": "nl_NL",
    "restrictPaymentMethodsToCountry": "NL",
    "expiresAt": "2018-03-20T13:28:37+00:00",
    "details": null,
    "profileId": "pfl_QkEhN94Ba",
    "sequenceType": "oneoff",
    "redirectUrl": "https://webshop.example.org/order/12345/",
    "webhookUrl": "https://webshop.example.org/payments/webhook/",
    "_links": {
        "self": {
            "href": "https://api.mollie.com/v2/payments/tr_WDqYK6vllg",
            "type": "application/hal+json"
        },
        "checkout": {
            "href": "https://www.mollie.com/payscreen/select-method/WDqYK6vllg",
            "type": "text/html"
        },
        "dashboard": {
            "href": "https://www.mollie.com/dashboard/org_12345678/payments/tr_WDqYK6vllg",
            "type": "application/json"
        },
        "documentation": {
            "href": "https://docs.mollie.com/reference/v2/payments-api/get-payment",
            "type": "text/html"
        }
    }
}

I want do put this JSON-format in a struct called Payment. I have done this already quite successful, except for the part _links in my response.

These are my structs:

#[derive(Serialize, Deserialize)]
    #[serde(rename_all = "camelCase")]
    pub struct Amount {
        currency: String,
        value: String,
    }

    #[derive(Serialize, Deserialize)]
    #[serde(rename_all = "camelCase")]
    pub struct Link {
        pub href: String,
        r#type: String,
    }

    #[derive(Serialize, Deserialize)]
    #[serde(rename_all = "camelCase")]
    pub struct Payment {
        #[serde(skip_serializing)]
        id: String,
        description: String,
        amount: Amount,
        redirectUrl: String,
        webhookUrl: String,
        pub links: HashMap<String, Link>,
        #[serde(skip_serializing)]
        pub status: String,
    }

Everything deserializes smoothly in my struct except the links-part. That gives the following runtime-error:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("missing field `links`", line: 44, column: 1)', src/main.rs:83:64
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

I have tried to rename links to _links, r#_links,... tried a tuple instead of a Link-struct... but nothing worked. Somehow Serde is not able to interpret the _links part from my response into a hashmap.

How can I solve this runtime-error?

Playground: Rust Playground

Because prefix-underscore names are often used in Rust to suppress the "unused variable" lint, Serde automatically renames _links to links. Actually, no. This happens only because you are using serde(rename_all = "camelCase"), which deletes all underscores. (Not sure why you were using that, since the field names are already camel cased...)

You can instead just tell Serde exactly what name to use for serialization:

       #[serde(rename = "_links")]
       pub links: HashMap<String, Link>,

(When you use serde(rename = "name"), the renamed field is not subject to being renamed again by rename_all.)

1 Like

Perfect, thanks a lot! You saved my nightsleep. :stuck_out_tongue: