2

我正在尝试在 actix Web 应用程序中创建一个 graphql 解析器(使用 async-graphql)。我正在做一个 me 查询,我从会话中获取用户 ID,并从数据库中获取用户。这是代码中最相关的部分

use async_graphql::*;
use anyhow::anyhow;
use actix_session::Session;
use async_graphql_actix_web::{Request, Response};

#[derive(Default, Debug)]
pub struct UserQuery;

struct User {
    id: i32,
    username: String,
    ...
}

#[Object] // <- ERROR (Squiggly lines) IS HERE
impl UserQuery {
    ...
    // Other resolvers are fine
    // But this one does not work

    async fn me(&self, ctx: &Context<'_>) -> actix_http::error::Result<User> {
        let actix_session = ctx.data_unchecked::<Shared<actix_session::Session>>();
        let user_id = actix_session.get::<i32>("user_id");

        if let Ok(Some(id)) = user_id {
            let pool = ctx.data_unchecked::<DbPool>();
            let user = sqlx::query_as!(User, "SELECT * FROM users WHERE id = $1", id)
                .fetch_one(pool)
                .await
                .map_err(|e| actix_http::error::ErrorBadRequest(e))?;
            return Ok(user);
        } else {
            Err(anyhow!("lsdhf")).map_err(|e| actix_http::error::ErrorBadRequest(e))?
        }
    }
}

/// A wrapper around e.g. sessions, to inject into the request
#[derive(Clone, Debug)]
pub struct Shared<T>(pub Option<SendWrapper<T>>);

impl<T> Shared<T> {
    pub fn new(v: T) -> Self {
        Self(Some(SendWrapper::new(v)))
    }
}

impl<T> Deref for Shared<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &*self.0.as_deref().clone().unwrap()
    }
}

pub async fn graphql(schema: web::Data<SchemaType>, req: Request, session: Session) -> Response {
    let sesh = Shared::new(session);

    schema.execute(req.into_inner().data(sesh)).await.into()
}

但我得到了错误

`(dyn actix_web::ResponseError + 'static)` cannot be sent between threads safely
the trait `std::marker::Send` is not implemented for `(dyn actix_web::ResponseError + 'static)`
required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn actix_web::ResponseError + 'static)>`
required because it appears within the type `std::boxed::Box<(dyn actix_web::ResponseError + 'static)>`
required because it appears within the type `actix_web::Error`
required because it appears within the type `std::result::Result<std::option::Option<i32>, actix_web::Error>`
required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9> {std::future::ResumeTy, &'r routes::graphql::Shared<actix_session::Session>, std::result::Result<std::option::Option<i32>, actix_web::Error>, i32, &'s sqlx::Pool<sqlx::Postgres>, &'t0 str, sqlx::postgres::PgArguments, sqlx::query::Query<'t1, sqlx::Postgres, sqlx::postgres::PgArguments>, [closure@/Users/sorenhansen/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.4.2/src/macros.rs:519:9: 519:102], sqlx::query::Map<'t2, sqlx::Postgres, [closure@/Users/sorenhansen/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.4.2/src/macros.rs:519:9: 519:102], sqlx::postgres::PgArguments>, impl std::future::Future, ()}`
required because it appears within the type `[static generator@src/graphql/user.rs:102:67: 115:6 for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9> {std::future::ResumeTy, &'r routes::graphql::Shared<actix_session::Session>, std::result::Result<std::option::Option<i32>, actix_web::Error>, i32, &'s sqlx::Pool<sqlx::Postgres>, &'t0 str, sqlx::postgres::PgArguments, sqlx::query::Query<'t1, sqlx::Postgres, sqlx::postgres::PgArguments>, [closure@/Users/sorenhansen/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.4.2/src/macros.rs:519:9: 519:102], sqlx::query::Map<'t2, sqlx::Postgres, [closure@/Users/sorenhansen/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.4.2/src/macros.rs:519:9: 519:102], sqlx::postgres::PgArguments>, impl std::future::Future, ()}]`
required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10> {std::future::ResumeTy, &'r graphql::user::UserQuery, &'s async_graphql::ContextBase<'t0, &'t1 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>>, tracing::Span, [static generator@src/graphql/user.rs:102:67: 115:6 for<'t11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22> {std::future::ResumeTy, &'t11 routes::graphql::Shared<actix_session::Session>, std::result::Result<std::option::Option<i32>, actix_web::Error>, i32, &'t12 sqlx::Pool<sqlx::Postgres>, &'t13 str, sqlx::postgres::PgArguments, sqlx::query::Query<'t14, sqlx::Postgres, sqlx::postgres::PgArguments>, [closure@/Users/sorenhansen/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.4.2/src/macros.rs:519:9: 519:102], sqlx::query::Map<'t15, sqlx::Postgres, [closure@/Users/sorenhansen/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.4.2/src/macros.rs:519:9: 519:102], sqlx::postgres::PgArguments>, impl std::future::Future, ()}], impl std::future::Future, tracing::instrument::Instrumented<impl std::future::Future>, ()}`
required because it appears within the type `[static generator@src/graphql/user.rs:101:5: 101:60 for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10> {std::future::ResumeTy, &'r graphql::user::UserQuery, &'s async_graphql::ContextBase<'t0, &'t1 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>>, tracing::Span, [static generator@src/graphql/user.rs:102:67: 115:6 for<'t11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22> {std::future::ResumeTy, &'t11 routes::graphql::Shared<actix_session::Session>, std::result::Result<std::option::Option<i32>, actix_web::Error>, i32, &'t12 sqlx::Pool<sqlx::Postgres>, &'t13 str, sqlx::postgres::PgArguments, sqlx::query::Query<'t14, sqlx::Postgres, sqlx::postgres::PgArguments>, [closure@/Users/sorenhansen/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.4.2/src/macros.rs:519:9: 519:102], sqlx::query::Map<'t15, sqlx::Postgres, [closure@/Users/sorenhansen/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.4.2/src/macros.rs:519:9: 519:102], sqlx::postgres::PgArguments>, impl std::future::Future, ()}], impl std::future::Future, tracing::instrument::Instrumented<impl std::future::Future>, ()}]`
required because it appears within the type `std::future::from_generator::GenFuture<[static generator@src/graphql/user.rs:101:5: 101:60 for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10> {std::future::ResumeTy, &'r graphql::user::UserQuery, &'s async_graphql::ContextBase<'t0, &'t1 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>>, tracing::Span, [static generator@src/graphql/user.rs:102:67: 115:6 for<'t11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22> {std::future::ResumeTy, &'t11 routes::graphql::Shared<actix_session::Session>, std::result::Result<std::option::Option<i32>, actix_web::Error>, i32, &'t12 sqlx::Pool<sqlx::Postgres>, &'t13 str, sqlx::postgres::PgArguments, sqlx::query::Query<'t14, sqlx::Postgres, sqlx::postgres::PgArguments>, [closure@/Users/sorenhansen/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.4.2/src/macros.rs:519:9: 519:102], sqlx::query::Map<'t15, sqlx::Postgres, [closure@/Users/sorenhansen/.cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.4.2/src/macros.rs:519:9: 519:102], sqlx::postgres::PgArguments>, impl std::future::Future, ()}], impl std::future::Future, tracing::instrument::Instrumented<impl std::future::Future>, ()}]>`
required because it appears within the type `impl std::future::Future`
required because it appears within the type `impl std::future::Future`
required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4> {std::future::ResumeTy, &'r graphql::user::UserQuery, &'s async_graphql::ContextBase<'t0, &'t1 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>>, impl std::future::Future, ()}`
required because it appears within the type `[static generator@src/graphql/user.rs:13:1: 13:10 for<'r, 's, 't0, 't1, 't2, 't3, 't4> {std::future::ResumeTy, &'r graphql::user::UserQuery, &'s async_graphql::ContextBase<'t0, &'t1 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>>, impl std::future::Future, ()}]`
required because it appears within the type `std::future::from_generator::GenFuture<[static generator@src/graphql/user.rs:13:1: 13:10 for<'r, 's, 't0, 't1, 't2, 't3, 't4> {std::future::ResumeTy, &'r graphql::user::UserQuery, &'s async_graphql::ContextBase<'t0, &'t1 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>>, impl std::future::Future, ()}]>`
required because it appears within the type `impl std::future::Future`
required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22, 't23, 't24, 't25, 't26, 't27, 't28, 't29, 't30, 't31, 't32, 't33, 't34, 't35, 't36> {std::future::ResumeTy, &'r graphql::user::UserQuery, &'s async_graphql::ContextBase<'t0, &'t1 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>>, impl std::future::Future, (), graphql::response_types::user_form_response::UserFormResponse, async_graphql::ContextBase<'t10, &'t11 async_graphql::Positioned<async_graphql::async_graphql_parser::types::SelectionSet>>, &'t12 graphql::response_types::user_form_response::UserFormResponse, &'t13 async_graphql::ContextBase<'t14, &'t15 async_graphql::Positioned<async_graphql::async_graphql_parser::types::SelectionSet>>, async_graphql::ContextBase<'t16, &'t17 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>>, &'t18 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>, std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = std::result::Result<async_graphql::Value, async_graphql::ServerError>> + std::marker::Send + 't19)>>, impl std::future::Future, models::user::User, &'t28 models::user::User, impl std::future::Future}`
required because it appears within the type `[static generator@src/graphql/user.rs:13:1: 13:10 for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22, 't23, 't24, 't25, 't26, 't27, 't28, 't29, 't30, 't31, 't32, 't33, 't34, 't35, 't36> {std::future::ResumeTy, &'r graphql::user::UserQuery, &'s async_graphql::ContextBase<'t0, &'t1 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>>, impl std::future::Future, (), graphql::response_types::user_form_response::UserFormResponse, async_graphql::ContextBase<'t10, &'t11 async_graphql::Positioned<async_graphql::async_graphql_parser::types::SelectionSet>>, &'t12 graphql::response_types::user_form_response::UserFormResponse, &'t13 async_graphql::ContextBase<'t14, &'t15 async_graphql::Positioned<async_graphql::async_graphql_parser::types::SelectionSet>>, async_graphql::ContextBase<'t16, &'t17 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>>, &'t18 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>, std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = std::result::Result<async_graphql::Value, async_graphql::ServerError>> + std::marker::Send + 't19)>>, impl std::future::Future, models::user::User, &'t28 models::user::User, impl std::future::Future}]`
required because it appears within the type `std::future::from_generator::GenFuture<[static generator@src/graphql/user.rs:13:1: 13:10 for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22, 't23, 't24, 't25, 't26, 't27, 't28, 't29, 't30, 't31, 't32, 't33, 't34, 't35, 't36> {std::future::ResumeTy, &'r graphql::user::UserQuery, &'s async_graphql::ContextBase<'t0, &'t1 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>>, impl std::future::Future, (), graphql::response_types::user_form_response::UserFormResponse, async_graphql::ContextBase<'t10, &'t11 async_graphql::Positioned<async_graphql::async_graphql_parser::types::SelectionSet>>, &'t12 graphql::response_types::user_form_response::UserFormResponse, &'t13 async_graphql::ContextBase<'t14, &'t15 async_graphql::Positioned<async_graphql::async_graphql_parser::types::SelectionSet>>, async_graphql::ContextBase<'t16, &'t17 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>>, &'t18 async_graphql::Positioned<async_graphql::async_graphql_parser::types::Field>, std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = std::result::Result<async_graphql::Value, async_graphql::ServerError>> + std::marker::Send + 't19)>>, impl std::future::Future, models::user::User, &'t28 models::user::User, impl std::future::Future}]>`
required because it appears within the type `impl std::future::Future`
required for the cast to the object type `dyn std::future::Future<Output = std::result::Result<std::option::Option<async_graphql::Value>, async_graphql::ServerError>> + std::marker::Send`rustcE0277

我应该怎么办?无论如何,我也尝试过错误,但没有运气。我认为错误与 sqlx 的东西有关,因为当我删除该query_as部分时,错误就消失了。

相关的依赖是

[dependencies]
actix-web = "3"
actix-session = "0.4.1"
actix-redis = "0.9.1"
actix-http = "2.2.1"
async-graphql = { version = "2.9.12", features = ["chrono", "log"] }
async-graphql-actix-web = "2.9.12"
send_wrapper = "0.5.0"
anyhow = "1.0.43"

如果有任何帮助,可以在这里找到整个仓库https://github.com/SorenHolstHansen/full-stack-starter

4

1 回答 1

1

尝试为您的函数使用actix_http::error::Resultas 返回类型。me


结果有不同的错误类型。

您的函数的返回anyhow::Result是使用anyhow::Erroras E

然而, Session get将使用ResponseError不是线程安全的。

此外,类型之间没有自动转换,您需要使用类似下面的方法将anyhow::Errors 转换为与 actix 兼容的错误。

returnsAnyhowErrors()
.map_err(|e| error::ErrorBadRequest(e))?

很难判断这是否是问题所在,但总的来说,对于 actix,我已经养成了尽可能晚地切换到 actix 结果的习惯,以便几乎在任何地方都继续使用无论如何错误。但是,在某些情况下,例如您的情况,这是不可能的,或者至少我还没有找到方法。

于 2021-09-09T22:59:24.300 回答