How to get Ok value return from the function?

I'm trying to return fetched data as a value from function, but i have problem unwrapping it? I'm no sure. I was looking for the answer, but there is no example covering that in reqwest nor serde. I'm not sure really how to form correct question but here is the code. I get error error[E0609]: no field id on type std::result::Result<Todo, reqwest::error::Error>. Inside fetch_data function keys are easily accessible, but after i call a function and store its return value into variable i can't access it. If i just print data i get Ok(Todo { userId: 1, id: 1, title: "delectus aut autem", completed: false }) so i think i need to somehow unwrapp it from Ok, but im not sure how. How to do that correctly? Thanks a lot.

use reqwest;
use serde::Deserialize;


fn main() {
    let data = fetch_data();
   println!("{:?}", data.id);
}

#[derive(Debug, Deserialize)]
struct Todo {
    userId: i32,
    id: i32,
    title: String,
    completed: bool,
}

#[tokio::main]
async fn fetch_data() -> Result<Todo, reqwest::Error> {

   let todo = reqwest::get("https://jsonplaceholder.typicode.com/todos/1")
    .await?
    .json::<Todo>()
    .await?;

    Ok(todo)

}

Okay, so, first. Putting #[tokio::main] on functions that are not the main function is not very common. There are situations where this makes sense, but please confirm whether this was what you intended.

The error you ran into is that fetch_data() returns a result, not a Todo. If you want a Todo, you need to handle possible errors. Consider reading chapter nine on error handling. Give this a try:

use reqwest;
use serde::Deserialize;

#[tokio::main]
async fn main() {
    let data = fetch_data().await.unwrap();
    println!("{:?}", data.id);
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] 
struct Todo {
    user_id: i32,
    id: i32,
    title: String,
    completed: bool,
}

async fn fetch_data() -> Result<Todo, reqwest::Error> {
    let todo = reqwest::get("https://jsonplaceholder.typicode.com/todos/1")
        .await?
        .json::<Todo>()
        .await?;

    Ok(todo)
}

I also fixed the use of camel case on the user id.

1 Like

I got another error | 19 | let data = fetch_data().await?.unwrap(); | ^^^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `std::result::Result<Todo, reqwest::error::Error>

Maybe i should not used async/await syntax? I wanted to use it because I thought that will be easier for me, since i'm familiar with this syntax from JS. I thought its not that complex and i can handle that.

The error is because you're using both the question mark operator and unwrap(). You're handling the error twice. Additionally, you forgot to remove #[tokio::main] from the other function. You should only have one of those. As for async/await, there are quite a lot of differences between Rust and Javascript's async world, and non-async code is simpler to work with.

If you want to use sync code instead, the reqwest crate also provides a module called blocking with non-async functions.

1 Like

Ok now i see my mistakes. Thanks a lot. Will read some more about error handling now!

Seems odd that we'd expect code that fetches an HTTP request asynchronously would always be in "main". Why does this restriction exist? I'm writing a service that dispatches multiple http requests asynchronously. I don't want to lump all that in main. It's in another Rocket handler. How do I use reqwest/tokio on other functions? Every example I see uses #[tokio::main] and it's driving me batty.

You can create a Runtime object and spawn futures on it instead of using the #[tokio::main] macro. Note that if you are using reqwest in a non-async library such as rocket, using the reqwest::blocking module is probably easier than creating a runtime object.

Thanks for the advice. Just been staring at this, realizing that async is contagious. Once you call something that's async, you need to await on it, and if you await, you need to be labeled async, and Rocket handlers can't be async. Trying to make it so results in:

^^^^^^ the trait rocket::response::Responder<'_> is not implemented for impl core::future::future::Future

I agree blocking would be easier. I did see the reqwest::blocking module, but this is partially an academic exercise. I want to show I can have a handler make asynchronous requests, merge the mess together, and come back when it's all done. Runtime will be the next attempt.

I guess I understand loosely now that #[tokio::main] starts up all the polling activity that the async/await implementation depends on. Seems like this just won't mix with Rocket handlers. As you say, it's a non-async library.

Thanks for the reply!

Yeah, to use Tokio inside rocket, you would have to call the block_on method in each handler.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.