website/content/blog/modifying-json-in-rust.md
2024-08-03 08:36:56 -07:00

3.2 KiB

title date draft tags math medium_enabled
Modifying JSON in Rust 2024-08-03T07:59:15-07:00 false
false false

For my new role, I've been learning Rust. I don't know why I didn't learn it earlier, I enjoy it so much that I decided to power my toots page with it.

When I query my toots, I receive a JSON response like the following:

[{"id": "112581869512127927", ..., "content": "...",}, ...]

Some parts of the JSON response changes quite frequently. Since I archive the changes, I want to strip out the highly dynamic information before saving it off to a file.

let mut json_response: serde_json::Value = serde_json::from_str("...")
	.expect("JSON parse error");

In order to modify this variable, we need to have some knowledge of it's structure. I'll show in this post how to modify our JSON data given whether we're working with a JSON array or a JSON object.

serde_json::Value::Array

Our example JSON starts off as an array, so let's extract that out:

let json_array = json_response
	.as_array_mut()
	.expect("Expected JSON Array");

The as_array_mut says to interpret the json_response variable as an array. The mut component is important for us to be able to edit the data in place without making copies.

The as_array_mut method returns an option type. Calling .expect(...) on it will cause the program to crash if it isn't indeed an array. We can alternatively perform some error handling:

if let Some(json_array) = json_response.as_array_mut() {
    // Do something with json_array
} else {
    // Error handling here
}

Though I'll assume that you're following best practices and not discuss more about error handling in this post.

Our variable json_array has type &mut Vec<serde_json::Value>which means we can do things like add another element to said array.

let new_element = serde_json::Value::from(1);
json_array.push(new_element);

We can also remove the last element of the array if it exists

json_array.pop()

serde_json::Value::Object

Within the array, we have a list of objects. Let us grab the first element as an example:

let first_item = json_array.get_mut(0).unwrap();

In order to be able to modify the data, we use the get_mut method. This, like before, returns an option if it doesn't exist. We can call unwrap on it to get access to the data or panic if the element doesn't exist.

The variable first_item has type serde_json::Value. To interpret this as an object, we need to call as_object_mut.

let first_item_obj = first_item.as_object_mut().unwrap();

Now our variable first_item_obj has type &mut Map<String, serde_json::Value>.

We can remove any fields that we don't think is important

first_item_obj.remove("bot");

Add any fields we want

let new_key = "PoweredBy".to_string();
let new_value = serde_json::Value::from("Rust");
toot.insert(new_key, new_value);

Renaming a field is the combination of the last two:

let toot_date = toot.remove("created_at")
	.expect("Missing created_at");
toot.insert("date".to_string(), toot_date);