[SOLVED]: Deserializing JSON with actix-web fails

⚓ rust    📅 2025-05-11    👤 surdeus    👁️ 4      

surdeus

Warning

This post was published 50 days ago. The information described in this article may have changed.

I started implementing my first API with rust. It looks like Actix-web is a very popular framework, so I thought to give it a spin.

However, linking my data types with the handlers isn't working yet.

I assume there are several issues here, so please bear with me.

First my types:

#[derive(Serialize, Deserialize)]
pub struct Reservation {
    pub id: i64,
    pub pub_key: Vec<u8>,
    pub expiry: u64,
    pub terms: Vec<u8>,
    pub sig: Vec<u8>,
    pub range: Range,
}

#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct Range {
    pub id: u64,
    pub expiry: Option<u64>,
    pub terms: Option<Vec<u8>>,
    pub slots: Vec<Slot>,
}

#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct Slot {
    pub id: u64,
    pub app_id: u64,
    pub reserved: Option<Vec<u8>>,
    pub consumed: bool,
    pub expiry: Option<u64>,
    pub terms: Option<Vec<u8>>,
}

I am already not sure how internally the deserialization of Vec<u8> has to work. Also, another doubt is on Option fields.

One of my handler looks like this:

pub async fn reserve(db: web::Data<ReserveDB>, item: web::Json<Reservation>) -> HttpResponse {
    let reservation = item.into_inner();
    match db.save_reservation(&reservation) {
    // prepare response   
    }
}

The server is started like this:

    #[actix_web::main]
    pub async fn start(&self) -> std::io::Result<()> {
        let settings = default_settings().expect("settings should have been set up");
        let reserve_db = match ReserveDB::new(settings) {
           // handle setting up db
        };

        HttpServer::new(move || {
            App::new()
                .wrap(Logger::default())
                .app_data(web::Data::new(reserve_db.clone()))
                .service(
                    web::scope("/api/v1")
                        .route("/reservation", web::put().to(handlers::reserve))
                )
        })
        .bind("127.0.0.1:8080")?
        .workers(2)
        .run()
        .await
    }

So far, every attempt to call this via curl failed with a deserialization error:

2025-05-11T22:45:32Z DEBUG actix_web::types::json] Failed to deserialize Json from payload. Request path: /api/v1/reservation
[2025-05-11T22:45:32Z DEBUG actix_web::middleware::logger] Error in response: ContentType
[2025-05-11T22:45:32Z INFO  actix_web::middleware::logger] 127.0.0.1 "PUT /api/v1/reservation HTTP/1.1" 400 18 "-" "curl/8.13.0" 0.000238

As you can see it seems as that I am also responding incorrectly. But if that is not relevant to this question, let's leave that out for now. I want to understand why it is not able to deserialize json correctly.

Here is one of the attempts at calling the endpoint, with a fully expanded Reservation struct:

curl -v -X PUT -d '{"id":-1,"pub_key":[1,2,3,4],"expiry":0,"terms":[33,33],"sig":[6,5,4,3],"range":{"id":1,"expiry":0,"terms":[1,2,3,3],"slots":[{"id":0,"app_id":42,"reserved":"","consumed":false,"expiry":0,"terms":[0]}]}}' -H: "Content-type: application/json" localhost:8080/api/v1/reservation

The byte values really don't matter for now, I am just interested to get the deserialization going right first. Is that the correct way of putting byte values in JSON?

I have also tried with just leaving out the nested struct fields:

curl -v -X PUT -H: "Content-type: application/json" -d '{"id":-1,"pub_key":[1,2,3,4],"expiry":0,"terms":[33,33],"sig":[6,5,4,3],"range":{}}' localhost:8080/api/v1/reservation

One of the other numerous attempts has involved "prefixing" the JSON object with the struct name:
-d {"reservation":{...}}

But that also didn't help.
I couldn't find much documentation in the serde docs specifically about byte vectors (did I just not look right?), but maybe I am not getting something way more basic yet. Or maybe I am oversimplifying things from looking at the (usual) simple example in the docs.

Can someone shed light here please? Thanks.

2 posts - 1 participant

Read full topic

🏷️ rust_feed