Future<Item = HttpResponse, Error = actix_web::Error> - 'Item' and 'Error' associated types not found?

234 views Asked by At

I am experimenting with Tokio, Reqwest and Actix-web and creating am API that connects to SendGrid to send simple emails.

I am stuck on an error:

error[E0220]: associated type `Item` not found for `std::future::Future`
  --> src\main.rs:20:79
   |
20 |     request: web::Json<EmailRequest>,) -> impl tokio::macros::support::Future<Item = HttpResponse, Error = actix_web::Error> {
   |                                                                               ^^^^ associated type `Item` not found

error[E0220]: associated type `Error` not found for `std::future::Future`
  --> src\main.rs:20:100
   |
20 |     request: web::Json<EmailRequest>,) -> impl tokio::macros::support::Future<Item = HttpResponse, Error = actix_web::Error> {
   |                                                                                                    ^^^^^ associated type `Error` not found

I may be limited in my understanding here but if the Future is from tokio, why is the error showing Item and Error not found for stduture::Future?

Here is my code:

extern crate actix_web;
extern crate reqwest;
extern crate tokio;
extern crate serde_json;
extern crate serde;

use actix_web::{web::{self, Json}, App, HttpResponse, HttpServer, http};
use reqwest::Client;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct EmailRequest {
    to: String,
    subject: String,
    text: String,
}

fn send_email(request: Json<EmailRequest>) -> impl tokio::macros::support::Future<Item=HttpResponse, Error=actix_web::Error> {
    
    // Set up the request body
    let body = serde_json::json!({
        "personalizations": [{
            "to": [{ "email": request.to }],
            "subject": request.subject,
        }],
        "from": { "email": "[email protected]" },
        "content": [{ "type": "text/plain", "value": request.text }],
    });

    // Create an HTTP client
    let client = Client::new();

    // Send the request
    client
        .post("https://api.sendgrid.com/v3/mail/send")
        .header("Authorization", "Bearer YOUR_API_KEY")
        .header("Content-Type", "application/json")
        .send_json(&body)
        .map_err(actix_web::Error::from)
        .and_then(|response| {
            if response.status() == http::StatusCode::ACCEPTED {
                Ok(HttpResponse::Ok().body("Email sent successfully!".to_string()))
            } else {
                Ok(HttpResponse::InternalServerError().body("Error sending email!".to_string()))
            }
        })
}

fn main() -> std::io::Result<()> {
    HttpServer::new(|| App::new().route("/api/send_email", web::post().to(send_email)))
        .bind("localhost:8080")?
        .run()
}

FYI, my cargo dependences are:

[dependencies]
reqwest = "0.11.13"
tokio = { version = "1", features = ["full"] }
actix-web = "4.2.1"
serde = { version = "1.0.152", features = ["derive"]}
serde_json = "1.0.91"

[features]
default = ["tokio/full"]

Any help would be much appreciated.

Ive tried using various crates but whenever I use a future I get a problem with the associated types. I did use Rocket but had a problem with the Outcome.

I am wondering if the issue is to do with the response from the client that is not matching the function output.

1

There are 1 answers

0
John Watson On

I made the following changes and it all worked a treat. I removed the Future and added the Async, I had to make a number of other changes as it through up some more issues but the following worked. Thanks for helping a learner out.

extern crate actix_web;
extern crate reqwest;
extern crate serde;
extern crate serde_json;
extern crate tokio;
    
use actix_web::{
    http,
    web::{self, Json},
    App, HttpResponse, HttpServer,
};
use reqwest::Client;
use serde::{Deserialize, Serialize};
    
#[derive(Debug, Serialize, Deserialize)]
struct EmailRequest {
    to: String,
    subject: String,
    text: String,
}
    
async fn send_email(request: Json<EmailRequest>) -> Result<HttpResponse, actix_web::Error> {
    // Set up the request body
    let body = serde_json::json!({
        "personalizations": [{
            "to": [{ "email": request.to }],
            "subject": request.subject,
        }],
        "from": { "email": "[email protected]" },
        "content": [{ "type": "text/plain", "value": request.text }],
    });
    
    // Create an HTTP client
    let client = Client::new();
    
    // Send the request
    let response = client
        .post("https://api.sendgrid.com/v3/mail/send")
        .header("Authorization", "Bearer YOUR_API_KEY")
        .header("Content-Type", "application/json")
        .json(&body)
        .send()
        .await
        .map_err(reqwest::Error::from).unwrap();
    
    if response.status() == http::StatusCode::ACCEPTED {
        Ok(HttpResponse::Ok().body("Email sent successfully!".to_string()))
    } else {
        Ok(HttpResponse::InternalServerError().body("Error sending email!".to_string()))
    }
}
    
#[tokio::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| App::new().route("/api/send_email", web::post().to(send_email)))
        .bind("localhost:8080")?
        .run()
        .await
}