> For the complete documentation index, see [llms.txt](https://bitcoin-dev-project.gitbook.io/rust-for-bitcoiners/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bitcoin-dev-project.gitbook.io/rust-for-bitcoiners/tutorials/json_serialization_with_serde.md).

# JSON\_serialization\_with\_serde

## JSON serialization with serde

Let's say we want to display our data in JSON format. A popular library that many Rust developers use is the [`serde_json`](https://docs.rs/serde_json/latest/serde_json/) crate.

### Setup

We can add this to our Cargo.toml file like so:

```toml
[package]
name = "serde_tutorial"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.115"
```

Note that we want to bring in the `derive` feature from `serde`. This will allow us to `derive` the `Serialize` implementation for our structs. We'll also bring in `serde_json` so that we can convert our struct to a JSON formatted `String`.

### Example

Let's take an example using a struct from the Rust-Bitcoin library:

```rust
pub struct TxOut {
    /// The value of the output, in satoshis.
    pub value: Amount,
    /// The script which must be satisfied for the output to be spent.
    pub script_pubkey: ScriptBuf,
}
```

So there are two different field types here, the `Amount` type and the `ScriptBuf` type. These are essentially just wrappers for other types in the form of tuple structs. Let's include those.

```rust
pub struct Amount(u64)
pub struct ScriptBuf(Vec<u8>)

pub struct TxOut {
    /// The value of the output, in satoshis.
    pub value: Amount,
    /// The script which must be satisfied for the output to be spent.
    pub script_pubkey: ScriptBuf,
}
```

Now we can add the `derive` attribute to `TxOut` for `Serialize` and see if this works by calling `serde_json::to_string_pretty` on our `TxOut` struct instance. Remember to bring `serde_json` and `serde::Serialize` into scope. You can follow along on [Rust Playground](https://play.rust-lang.org/?version=stable\&mode=debug\&edition=2021\&gist=a76739816ac2a17b268a58064dde24b6).

```rust
use serde_json;
use serde::Serialize;

pub struct Amount(pub u64);
pub struct ScriptBuf(pub Vec<u8>);

#[derive(Serialize)]
pub struct TxOut {
    /// The value of the output, in satoshis.
    pub value: Amount,
    /// The script which must be satisfied for the output to be spent.
    pub script_pubkey: ScriptBuf,
}

fn main() -> () {
    let amount = Amount(1_000_000);
    let script_pubkey = ScriptBuf(vec![0, 0, 0, 0]);

    let txout = TxOut {
        amount,
        script_pubkey,
    };

    let json_txout = serde_json::to_string_pretty(&txout).unwrap();

    println!("{}", json_txout);
}
```

This, of course, won't work. We need to implement the `Serialize` trait for both the `ScriptBuf` and `Amount`. This trait is already implemented by default for most primitive and standard types. However, since these are custom types we'll need to implement the `Serialize` trait for each of them.

## Problem Statement

Implement the `Serialize` trait for the `Amount` and `ScriptBuf` structs.

### Implementation

When implementing the `Serialize` trait, we must implement the required method, `serialize`. This is the method signature: `fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error>`. It accepts a type which implements the `Serializer` trait. This type will be passed in by `serde_json` when we call the `to_string_pretty` method. The `Serializer` trait has several methods available that we can use to serialize various types, which can be found in the [documentation](https://docs.rs/serde/latest/serde/ser/trait.Serializer.html).

Let's start with a simple version, leveraging the methods available for the `Serializer` trait.

```rust
...

impl Serialize for Amount {
    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        s.serialize_u64(self.0)
    }
}

impl Serialize for ScriptBuf {
    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        s.serialize_bytes(self.0.as_slice())
    }
}

...
```

Notice that we use the `serialize_u64` and `serialize_bytes` methods. The `serialize_bytes` method accepts a `slice` as an argument so we'll call the `.as_slice` method on the `Vec`.

This will now work and print the json output we expect:

```console
{
  "value": 1000000,
  "script_pubkey": [
    0,
    0,
    0,
    0
  ]
}
```

### Separating display from storage

However, there's another problem. We want to print the `Amount` in bitcoin and not satoshis. We want to store it in satoshis for internal purposes but serialize it as a bitcoin amount for display purposes.

With `serde` we can provide custom serialization at the field level. See [documentation](https://serde.rs/field-attrs.html#serialize_with) for various field attributes that we can add. This is useful when we want to serialize `Amount` differently based on its context.

We can do something like the following:

```rust
#[derive(Serialize)]
...

pub struct TxOut {
    /// The value of the output, in satoshis.
    #[serde(serialize_with = "as_btc")]
    pub value: Amount,
    /// The script which must be satisfied for the output to be spent.
    pub script_pubkey: ScriptBuf,
}

...
```

The `as_btc` method accepts a generic type `T` so we'll set up a new trait called `SerdeAmount` and implement the `ser_btc` method.

```rust
...

trait SerdeAmount {
    fn ser_btc(&self) -> f64;
}

impl SerdeAmount for Amount {
    fn ser_btc(&self) -> f64 {
        self.0 as f64 / 100_000_000.0
    }
}

#[derive(Serialize)]
pub struct TxOut {
    /// The value of the output, in satoshis.
    #[serde(serialize_with = "as_btc")]
    pub value: Amount,
    /// The script which must be satisfied for the output to be spent.
    pub script_pubkey: ScriptBuf,
}

fn as_btc<T: SerdeAmount, S: Serializer>(t: &T, s: S) -> Result<S::Ok, S::Error> {
    s.serialize_f64(t.ser_btc())
}

...
```

The full code is available on [Rust-Playground](https://play.rust-lang.org/?version=stable\&mode=debug\&edition=2021\&gist=aa0ad5300c3c991be47b1943e3c63d21).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bitcoin-dev-project.gitbook.io/rust-for-bitcoiners/tutorials/json_serialization_with_serde.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
