Search code examples
rustserdeserde-json

How do I change Serde's default implementation to return an empty object instead of null?


I'm developing an API wrapper and I'm having some troubles with the deserialization of an empty JSON object.

The API returns this JSON object. Mind the empty object at entities:

{
  "object": "page",
  "entry": [
    {
      "id": "1158266974317788",
      "messaging": [
        {
          "sender": {
            "id": "some_id"
          },
          "recipient": {
            "id": "some_id"
          },
          "message": {
            "mid": "mid.$cAARHhbMo8SBllWARvlfZBrJc3wnP",
            "seq": 5728,
            "text": "test",
            "nlp": {
              "entities": {} // <-- here
            }
          }
        }
      ]
    }
  ]
}

This is my equivalent struct of the message property (edited):

 #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TextMessage {
    pub mid: String,
    pub seq: u64,
    pub text: String,
    pub nlp: NLP,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct NLP {
    pub entities: Intents,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Intents {
    intent: Option<Vec<Intent>>,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Intent {
    confidence: f64,
    value: String,
}

Serde's default is to deserialize Options, which are None, with ::serde_json::Value::Null.


Solution

  • I solved this problem differently with no need to change the default implementation. I used serde's field attributes to skip the intent property when the Option is None. Because there is only one property in the struct Intents, this will create an empty object.

    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct TextMessage {
        pub mid: String,
        pub seq: u64,
        pub text: String,
        pub nlp: NLP,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct NLP {
        pub entities: Intents,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct Intents {
        #[serde(skip_serializing_if="Option::is_none")]
        intent: Option<Vec<Intent>>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct Intent {
        confidence: f64,
        value: String,
    }