7

I'm trying to make a webserver that accepts some parameters as JSON, and turns them into a struct which I'll then store somewhere else in my app.

I have this data struct in a file called status.rs:

use serde::{Serialize, Deserialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Status {
    pub id: String,
    pub rssi: Option<i8>,
    pub carrier: Option<String>,
    pub timestamp: u64,
}

I am then using the following code inside a service in Hyper to try to parse the body of the request and turn it into my struct. The only difference is that I want to add the timestamp field according to the timestamp on the server, not on the client:

let timestamp: u64 = SystemTime::now()
    .duration_since(UNIX_EPOCH)
    .expect("PANIC! Time is running backwards!")
    .as_secs();

Box::new(req.into_body().concat2().map(|body| {
    let body_bytes = body.into_bytes();
    let body_str = match str::from_utf8(&body_bytes) {
        Ok(v) => v,
        Err(e) => {
            // TODO: this is shitty error handling
            panic!("Unable to read UTF8 input: {}", e);
        }
    };
    let input_data: Value = serde_json::from_str(body_str).unwrap();
    let data = Status {
        id: input_data.get("id").unwrap(),
        timestamp: timestamp,
        rssi: input_data.get("rssi"),
        carrier: input_data.get("carrier"),
    };

    update(data);
}));

The update function just inserts it into a data storage structure.

I have tried doing this in several different ways, but this way gives me the problem that each one of these fields is of type Option<&Value> (I think).

Hopefully the outcome I'm trying to achieve is clear enough, I just have no idea how to take the request body, parse the JSON, add in a timestamp, and package it up in a struct which I then store in my database.

How should I go about this?

GTF
  • 8,031
  • 5
  • 36
  • 59

1 Answers1

5

You're trying to convert body to byte slice, then to string, then to serde_json::Value, then to Status. Quite a lot of unnecessary intermediate steps, right? Just read the docs:

let body = req.into_body().concat2().wait().unwrap().into_bytes();
let s: Status = serde_json::from_slice(&body).unwrap();

Laney
  • 1,571
  • 9
  • 7
  • Thanks, that is definitely better but I’m still not sure how to go about adding this extra timestamp field which is not an `Option` (because a `Status` isn’t valid without one) since it isn’t included in the request body. – GTF Feb 17 '19 at 12:11
  • 5
    calling wait blocks indefinitely for me since it's in the hyper request handler. – Justin Thomas May 09 '19 at 13:30