Deserializing Objects with Unknown Fields in Rust

Samuel Beaulieu
TarkaLabs TIL
Published in
2 min readAug 9, 2022
Dall-E mini AI-Generated image from Huggingface.co

When deserializing objects, there are situations where we may not know the name(s) of one or more fields. For example, the Slack API’s response format is composed of an ok field, optional warning and error fields, and a field containing the requested data. The field for this data could be named after any of the Slack API objects, from profile to view. Here’s some examples of potential responses:

{"ok": true, "profile": {...}}
{"ok": false, "error": "not_authed"}
{"ok": true, "view": {...}}

Optional Fields

Since error only exists when ok is false, we can declare the type of error in our struct as Option<String>. Thus, the deserializer can add the value None to error if the request was successful and deserialize the error field if something went wrong.

Distinct Fields

For fields where we don’t know the name, but know the set of possibilities, we can use enums. Serde will use a match pattern and attempt each variant until it successfully deserializes the object.

#[derive(Serialize, Deserialize)]
enum SlackResponse {
ProfileResp { ok: bool, profile: Profile, error: Option<String> },
ViewResp { ok: bool, view: View, error: Option<String> },
}

If the number of variants expected is too great or the field names are random, HashMaps are another option. We can use the serde_json crate to turn any JSON object or any other object that could be interpreted as JSON into a HashMap<String, Value>. This way, it is possible to deserialize first and iterate through the HashMap to search for fields afterward.

let map =  serde_json::from_slice::<HashMap<String, Value>(&bytes)?;
let profile = map.get("profile").unwrap();

Using these methods, deserializing objects in Rust is quick and easy, regardless of the format.

--

--