diff --git a/content/blog/modifying-json-in-rust.md b/content/blog/modifying-json-in-rust.md new file mode 100644 index 0000000..08cdf09 --- /dev/null +++ b/content/blog/modifying-json-in-rust.md @@ -0,0 +1,103 @@ +--- +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); +``` +