Pro Poop
Pro Poop

Reputation: 446

How to handle nested JSON objects in reqwest?

I am using reqwest to perform a GET request from https://httpbin.org. Performing a request to a one-level json endpoint like https://httpbin.org/ip is easy

use std::collections::HashMap;

fn main() {
    let body = reqwest::blocking::get("https://httpbin.org/ip")
        .unwrap()
        .json::<HashMap<String, String>>()
        .unwrap();
    dbg!(body);
}

However Im not sure how to go about other endpoints with a multi-level JSON response. How can I make a request to a multi-level JSON endpoint in reqwest?

use std::collections::HashMap;

fn main() {
    let body = reqwest::blocking::get("https://httpbin.org/get")
        .unwrap()
        .json::<HashMap<K, V>>()
        .unwrap();
    dbg!(body);
}

Upvotes: 4

Views: 1655

Answers (1)

Caesar
Caesar

Reputation: 8484

Deserializing into serde_json::Value, as @BallpointBen suggests certainly works. But in many cases, you'll then need to manually extract data from an arbitrary json value, which is tedious. There is a nicer way: deserialize into a rust struct:

struct Response { /* … */ }

let body = reqwest::blocking::get("https://httpbin.org/get?arg=blargh")
    .unwrap()
    .json::<Response>()
    .unwrap();

To make that happen, you need to explain to serde how to work with your struct, e.g. like this:

use std::{collections::HashMap, net::IpAddr};
use serde::Deserialize;

#[derive(Deserialize)]
struct Response {
    args: HashMap<String, String>,
    // I'm making headers into another struct here to show some possibilities. You can of course make it a HashMap like args
    headers: ResponseHeaders,
    origin: IpAddr,
    url: url::Url,
}

#[derive(Deserialize)]
#[serde(rename_all = "PascalCase")]
struct ResponseHeaders {
    accept: String,
    host: String,
    #[serde(flatten)]
    dynamic: HashMap<String, String>,
}

Deserializing into native rust structs is a bit of a rabbit hole, there's an small book on it.

Upvotes: 2

Related Questions