--- title: "Modifying JSON in Rust" date: 2024-08-03T07:59:15-07:00 draft: false tags: [] math: false medium_enabled: 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](/toots) page with it. When I query my toots, I receive a JSON response like the following: ```json [{"id": "112581869512127927", ..., "content": "...",}, ...] ``` Some parts of the JSON response changes quite frequently. Since I [archive](https://brandonrozek.com/blog/archiving-toots/) the changes, I want to strip out the highly dynamic information before saving it off to a file. ```rust 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: ```rust 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: ```rust 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`which means we can do things like add another element to said array. ```rust 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 ```rust 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: ```rust 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`. ```rust let first_item_obj = first_item.as_object_mut().unwrap(); ``` Now our variable `first_item_obj` has type `&mut Map`. We can remove any fields that we don't think is important ```rust first_item_obj.remove("bot"); ``` Add any fields we want ```rust 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: ```rust let toot_date = toot.remove("created_at") .expect("Missing created_at"); toot.insert("date".to_string(), toot_date); ```