我正在尝试在 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