Code Review for a Beginner

Hi all,

Just taken up an opportunity to allocate some of my time to learning Rust.

I was quite comfortable following the book up until smart pointers. I will be coming back to that once I'm comfortable with the language as it was covered up to that point.

I've done a few things on Exercism and then wanted to try something different.

The following main.rs tries to get 10 news items from the Guardian API and displays their titles.

In the next iteration, I'd like to add functionality to be able to select an item and read its text contents.

I'd be extremely glad if you guys could provide me with some feedback on the code I've written. I've started reading about Rust only 3 days ago, so I can use any bit of feedback, no matter if it seems trivial for experienced Rustaceans.

Many thanks.

#[macro_use]
extern crate dotenv_codegen;

use std::io::Read;
use serde_json::Value;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Response {
    current_page: u32,
    order_by: String,
    page_size: u32,
    pages: u32,
    results: Vec<Items>,
    start_index: u32,
    status: String,
    total: u32,
    user_tier: String,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Items {
    api_url: String,
    web_title: String,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let key = dotenv!("GUARDIAN_API_KEY");
    let url = format!("https://content.guardianapis.com/search?api-key={}", key);

    let mut res = reqwest::blocking::get(&url)?;
    let mut body = String::new();
    res.read_to_string(&mut body)?;

    let json: Value = serde_json::from_str(&body).unwrap_or_else(|e| {
        panic!("Failed to parse json; error is {}", e);
    });

    let response: Response = serde_json::from_value(json["response"].clone()).unwrap_or_else(|e| {
        panic!("Failed to parse json; error is {}", e);
    });

    for result in response.results {
        println!("{}", result.web_title);
    }

    Ok(())
}

I would probably prefer to do this:

#[derive(Debug, Serialize, Deserialize)]
struct HasResponse {
    response: Response,
}

let json: HasResponse = serde_json::from_str(&body).unwrap_or_else(|e| {
    panic!("Failed to parse json; error is {}", e);
});
let response = json.response;

Unnecessarily going through Value is rather inefficient.

1 Like

Hi @alice ,

Thank you very much for your feedback.

It never occurred to me that I could refer to the "response" item using dot notation.

This makes it much cleaner and like you said definitely more efficient with all the cloning going on there.

Thanks again.