How to Use Multiple Types for A Field in Serde JSON?

Telegram bot API responds as below*:

// this JSON will have comments, thus invalid
{
  "ok": true,
  "error_code": 404,  // if "ok" is false. can be absent.
  "description": null,  // if "ok" is false. can be null.
  "result": { ... }  // if "ok" is true. it has types.
}

result key has possible types, one of which is User. Assuming I derive Deserialize for a User struct I create as below:

#[derive(Deserialize)]
struct User {
    // fields of User here, see link above
}

...and presumably all the other types of Telegram bot API. And a struct called GenericResponse:

#[derive(Deserialize)]
struct GenericResponse {
    ok: bool,
    error_code: u32,
    description: String,
    result:  // so what is this going to be?
}

It will has many types. How can you deal with a key having multiple possible types?

If there's no indication (besides structure) of result's type, you can use the untagged enum representation. This will try deserializing to each variant in turn until a matching one is found:

#[derive(Deserialize)]
struct GenericResponse {
    ok: bool,
    error_code: u32,
    description: String,
    result: GenericResponseResult
}

#[derive(Deserialize)]
#[serde(untagged)]
enum GenericResponseResult {
    User(User),
    // Other possible response types here...
}
3 Likes

The documentation rather tells:

Response { id: String, result: Value }

...instead of...

Response(Response)

Are you sure it is User(User)?

If I'm not mistaken, you can either define the User type inline as an enum variant:

#[derive(Deserialize)]
#[serde(untagged)]
enum GenericResponseResult {
    User { user_field_1: String },
}

Or seperately:

#[derive(Deserialize)]
#[serde(untagged)]
enum GenericResponseResult {
    User(User),
}

#[derive(Deserialize)]
struct User {
    user_field_1: String,
}

And they'll be deserialized the same. Depends if you ever want to use User seperately from GenericResponseResult.

1 Like