skip to Main Content

I’m working with an API that sometimes returns null values for certain fields. I’m using Rust to fetch and process this data, but I want to ensure that structs containing optional string fields deserialize correctly.

Currently, I’m using #[serde(default)] for the description field in my struct:

use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize)]
struct Info {
  #[serde(default)]
  description: String, // Use default value for missing description
}

However, my goal is to handle potential null values in the API response and make sure deserialization works as expected.

Are there any recommendations for further improvement or alternative approaches I should consider for handling optional string values during deserialization?

2

Answers


  1. The way I typically handle this is to use Option<String>. Then, if the value is null, you get a None, and if the value is a string, you get Some(String). That works for JSON, CBOR, and most related serialization formats where you can have either a string or a null.

    If you want to then use a default value, you can do so, like so:

    fn say_something(d: Option<&str>) {
        println!("{}", d.unwrap_or("abc"));
    }
    
    fn main() {
        let d: Option<String> = None;
        say_something(d.as_deref());
        let d = Some("def".to_string());
        say_something(d.as_deref());
    }
    
    Login or Signup to reply.
  2. To supplement the other answer, it is possible to handle this case without typing description as an Option<String> (should you not want it to be an Option) and even specifying some other value to use instead of the empty string if the value is missing or null. You can do this using #[serde(default)] and #[serde(deserialize_with)] like this:

    use serde::{Deserialize, Deserializer, Serialize};
    
    #[derive(Debug, Deserialize, Serialize)]
    struct Info {
        #[serde(default = "default_description")]
        #[serde(deserialize_with = "deser_description")]
        description: String, // Use default value for missing description
    }
    
    fn default_description() -> String {
        "(missing description)".to_owned()
    }
    
    fn deser_description<'de, D: Deserializer<'de>>(deserializer: D) -> Result<String, D::Error> {
        Option::deserialize(deserializer).map(|s| s.unwrap_or_else(default_description))
    }
    
    fn main() {
        let info: Info = serde_json::from_str(r#"{"description":null}"#).unwrap();
        assert_eq!(info.description, default_description());
    
        let info: Info = serde_json::from_str(r#"{}"#).unwrap();
        assert_eq!(info.description, default_description());
    }
    

    (Playground)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search