András Krausz
András Krausz

Reputation: 75

Simpler way to generate json body for reqwest post

I have a post call that adds one line in register, it works but a pain in the back to write and look at. This is how it looks:

static CLIENT: Lazy<Client> = 
    Lazy::new(|| Client::new());
static GENERATED_TOKEN: Lazy<GeneratedToken> =
    Lazy::new(|| get_token().expect("failed to get token"));

fn get_token() -> Result<GeneratedToken, Box<dyn std::error::Error>> {
    ...
    Ok(generated_token)
}


fn register(email: &str, pw: &str) -> bool {
    let body = String::from("") + "{
        \"table_name\": \"admin\",
        \"row\": {
            \"email\": \"" + email + "\", \"password\": \"" + pw + "\"
        }
    }";

    let response = CLIENT
        .post(format!("{SEATABLE_BASE_URL}dtable-server/api/v1/dtables/{}/rows/", GENERATED_TOKEN.dtable_uuid))
        .header(AUTHORIZATION, format!("Bearer {}", GENERATED_TOKEN.access_token))
        .header(ACCEPT, "application/json")
        .header(CONTENT_TYPE, "application/json")
        .body(body)
        .send().is_ok();

    println!("Registration successful with email \"{email}\": {response}");
    response
}

fn main() {
    Lazy::force(&CLIENT);
    println!("Has CLIENT");
    Lazy::force(&GENERATED_TOKEN);
    println!("Has TOKEN?: {}", (GENERATED_TOKEN.access_token.len() > 0).to_string());

    register("email", "pw");
}

So how can I make the request body in a better way? I know there is a .json() method for reqwest, that sends a Map, but it didn't work for me.

These are the Cargo.toml dependencies:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
reqwest = { version = "0.11", features = ["json", "blocking"] }
lazy_static = "1.4.0"
once_cell = "1.18.0"

Upvotes: 2

Views: 2272

Answers (1)

cafce25
cafce25

Reputation: 27550

You can use the json!() macro to write inline json using variables from the current scope:

let json = &serde_json::json!({
    "table_name": "admin",
    "row": {
        "email": email,
        "password": pw
    }
});

let request = CLIENT.post("your_url")
    .json(json);

But if you plan on working with the data more than just passing it to a RequestBuilder you should probably just define custom datatypes:

fn register(u: &str, p: &str) {
    let request = Client::new().post("the url").json(&RegistrationData::new(u, p));
}

impl<'a> RegistrationData<'a> {
    fn new(user: &'a str, password: &'a str) -> Self {
        RegistrationData {
            table_name: "admin",
            row: Row { user, password },
        }
    }
}

#[derive(serde::Serialize)]
struct RegistrationData<'a> {
    table_name: &'a str,
    row: Row<'a>,
}
#[derive(serde::Serialize)]
struct Row<'a> {
    user: &'a str,
    password: &'a str,
}

Upvotes: 6

Related Questions