Sam Gomena
Sam Gomena

Reputation: 1479

Serde deserialization of partial structs with actix_web

I have an API endpoint that utilizes actix_web to deserialize an incoming JSON payload (actix_web ultimately uses serde for JSON deserialization).

As an example, I have something that looks like this:

pub struct IncomingPayload {
    pub field1: i32,
    pub field2: String
}

pub async fn update_platforms(
    pool: web::Data<Pool>,
    req: web::Json<Vec<IncomingPayload>>,
) -> Result<HttpResponse, error::Error> { 
    println!(req.field1); // will be an i32
    println!(req.field2); // will be a String
}

Currently, this endpoint will only successfully return if serde is able to deserialize all fields of the struct. I.e. A request must contain field1 and field2 keys.

E.g. this would be successful:

curl --header "Content-Type: application/json" \
  --request POST \
  --data '{"field1": 1,"field2":"something"}' \
  http://localhost:8080

But this would not (because field2 is missing from the payload):

curl --header "Content-Type: application/json" \
  --request POST \
  --data '{"field1": 1}' \
  http://localhost:8080

So my question is, can this be done? Can one send a JSON payload with a subset of key-value fields to an actix_web endpoint that expects all the fields to be present?

Or rather, is there a generic way to deserialize partial structs like this with actix_web or serde?

Upvotes: 3

Views: 2659

Answers (1)

Freyja
Freyja

Reputation: 40814

You can use Option<T> as the type for a field to have it be optional. If a field is missing during deserialization, the field is set to None, otherwise it is set to Some(value).

#[derive(Deserialize)]
struct IncomingPayload {
    pub field1: Option<i32>,
    pub field2: Option<String>,
}

For types that implement Default, you can also use the #[serde(default)] to set the field to the default value if the field is missing.

#[derive(Deserialize)]
struct IncomingPayload {
    #[serde(default)] // default = 0
    pub field1: i32,
    #[serde(default)] // default = empty string
    pub field2: String,
}

Upvotes: 8

Related Questions