How to correctly map a vector into another?


#1

Hi, I currently struggle trying to map a vector into another. Say I have this JSON: https://api.github.com/users/donaldpipowitch/repos

And I want map over the response to get an array/vector which only contains the name, fork and description. In JS I’d do this:

const repos = response.map(repo => ({ name: repo.name, fork: repo.fork, description: repo.description }));

Or that way:

const repos = response.map(({ name, fork, description }) => ({ name, fork, description }));

I already managed to parse my response with serde. Without correct deserializing (for which I need a nightly version of rust…?) everything is wrapped in a Value type which represents every possible JSON type (string, boolean, number and so on). I thought I’d need to match each type case, but I didn’t come far:

extern crate hyper;
extern crate serde;
extern crate serde_json;

use std::io::Read;
use hyper::Client;
use hyper::header::{Headers, UserAgent};
use serde_json::{Value, from_str};

fn main() {
    let url = "https://api.github.com/users/donaldpipowitch/repos";

    let mut headers = Headers::new();
    headers.set(UserAgent("test".to_string()));  // GitHub API needs a user agent

    let client = Client::new();
    let mut res = client.get(url)
        .headers(headers)
        .send()
        .expect("Couldn't send request.");

    let mut buf = String::new();
    res.read_to_string(&mut buf).expect("Couldn't read response.");

    if res.status.is_client_error() {
        panic!("Got client error: {}", res.status);
    }
    if res.status.is_server_error() {
        panic!("Got server error: {}", res.status);
    }

    // parse json
    let value: Value = from_str(&buf).unwrap();

    let value_arr = match value.as_array() {
        None => panic!("Couldn't parse json."),
        Some(value_arr) => value_arr,
    };

//    Here I tried to just get `name` to make it easier for me. But didn't work.
//    let repos: Vec<String> = value_arr.into_iter().map(|x| match x.as_object() {
//        None => panic!("Couldn't parse json."),
//        Some(value_obj) => value_obj.get("name"),
//    }).collect();
}

There must be a better way, right?


#2

I would recommend using nightly to use serde_json with the derive macro, it will make your life a lot easier. The compiler macros look like they are already on their way to be stablized so it will eventually make it into the stable build.

If you prefer to not use nightly, you can always use syntex, whose instructions are described here https://serde.rs/codegen-stable.html, in order to generate the serde aware structs.

Once you do either of those things, you can simply do something like:

#[derive(Deserialize)]
struct Response {
  name: String,
  fork: String,
  description: String
}

and then mapping a list of those structs should be easy


#3

Thank so far. So it sounds like it is not worth the effort of trying to extract the needed data on my own? I’ll try using nightly then.