jsonrustreqwest

cannot move out of `*response` which is behind a shared reference with Rust while parsing a json response


I'm a newbie that is trying to make a simple email parser, but I'm facing the usual newcomers' problems with the borrowing stuff in Rust.

I'm trying to make compile the following code that wants to parse a json response with reqwest into my struct MessagesListResponse and then I just want to return a Vec of strings only containing the mapped ids:

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct MessagesListResponse{
    messages: Vec<MessageId>
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct MessageId{
    id: String,
    thread_id: String
}


#[async_trait]
impl MessageGetter for GmailMessageGetter{

    async fn get_message_ids(&self) -> Vec<String> {
        

        let url = "https://gmail.googleapis.com/gmail/v1/users/me/messages?q=from%3Awebank%40webank.it%20subject%3Aautorizzato%20pagamento".to_owned();
        
        dbg!(&url);
        let response = &self.client.get(url).send().await.unwrap();

        _ = &response.error_for_status_ref().unwrap();
        let msg_list_response = response.json::<MessagesListResponse>().await.unwrap();
        msg_list_response.messages.into_iter().map(|message_id| message_id.id).collect()
    }
    
}

unfortunately I keep getting the error

cannot move out of `*response` which is behind a shared reference

at the line

let msg_list_response = response.json::<MessagesListResponse>().await.unwrap();

but I'm not understanding how to make it work because the response type reqwest::async_impl::response is not cloneable and the response.json method consumes the response. Can I get some help? Thanks a lot.


Solution

  • There's an unnecessary reference here.

    let response = &client.get(url).send().await.unwrap();
    

    Remove it, and your code works.

    let response = client.get(url).send().await.unwrap();
    

    The assignment and reference here are unnecessary and do nothing.

    _ = &response.error_for_status_ref().unwrap();
    

    You can remove them.

    response.error_for_status_ref().unwrap();
    

    The .to_owned() at the end of the URL is also unnecessary. You should remove it.

    Those are the only issues, but another way to write this is as one big method chain.

    client
        .get(url)
        .send()
        .await
        .unwrap()
        .error_for_status()
        .unwrap()
        .json::<MessagesListResponse>()
        .await
        .unwrap()
        .messages
        .into_iter()
        .map(|message_id| message_id.id)
        .collect()