Reputation: 1479
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
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