This commit is contained in:
Brandon Rozek 2024-08-03 08:36:56 -07:00
parent 1e96cdae1b
commit 8a6f05fdc5
No known key found for this signature in database
GPG key ID: 26E457DA82C9F480

View file

@ -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<serde_json::Value>`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<String, serde_json::Value>`.
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);
```