idkthings_core 0.1.1

core stuff for idkthings
Documentation
extern crate core;

pub mod auth;
mod db;

use async_graphql::{ObjectType, Schema, SubscriptionType};
use async_graphql_poem::GraphQLRequest;
use async_graphql_poem::GraphQLResponse;
use async_trait::async_trait;
use poem::{Endpoint, EndpointExt};
use sqlx::PgPool;

use crate::auth::MaybeCurrentUserMiddleware;
use crate::db::create_db_client;
use poem::FromRequest;
use poem::Request;
use poem::{listener::TcpListener, post, Route, Server};

pub use log;
pub use sqlx;

pub async fn start_graphql_server<Query, Mutation, Subscription, RequestTransformer>(
    port: usize,
    query: Query,
    mutation: Mutation,
    subscription: Subscription,
    request_transformer: RequestTransformer,
) where
    Query: ObjectType + Default + 'static,
    Mutation: ObjectType + Default + 'static,
    Subscription: SubscriptionType + Default + 'static,
    RequestTransformer: FnMut(Request, async_graphql::Request) -> async_graphql::Request
        + Send
        + Sync
        + Clone
        + 'static,
{
    env_logger::init();
    let schema = Schema::build(query, mutation, subscription)
        .enable_federation()
        .finish();

    let pg_pool = create_db_client().await;

    let app = Route::new()
        .at(
            "/graphql",
            post(IndexEndpoint {
                schema,
                request_transformer,
            }),
        )
        .with(MaybeCurrentUserMiddleware {
            pg_pool: pg_pool.clone(),
        })
        .data::<PgPool>(pg_pool);

    Server::new(TcpListener::bind(format!("0.0.0.0:{}", port)))
        .run(app)
        .await
        .unwrap();
}

struct IndexEndpoint<Query, Mutation, Subscription, RequestTransformer>
where
    Query: ObjectType + Default + 'static,
    Mutation: ObjectType + Default + 'static,
    Subscription: SubscriptionType + Default + 'static,
    RequestTransformer: FnMut(Request, async_graphql::Request) -> async_graphql::Request
        + Send
        + Sync
        + Clone
        + 'static,
{
    pub schema: Schema<Query, Mutation, Subscription>,
    pub request_transformer: RequestTransformer,
}

#[async_trait]
impl<Query, Mutation, Subscription, RequestTransformer> Endpoint
    for IndexEndpoint<Query, Mutation, Subscription, RequestTransformer>
where
    Query: ObjectType + Default + 'static,
    Mutation: ObjectType + Default + 'static,
    Subscription: SubscriptionType + Default + 'static,
    RequestTransformer: FnMut(Request, async_graphql::Request) -> async_graphql::Request
        + Send
        + Sync
        + Clone
        + 'static,
{
    type Output = GraphQLResponse;

    async fn call(&self, req: Request) -> poem::Result<Self::Output> {
        let (req, mut request_body) = req.split();
        let graphql_request = GraphQLRequest::from_request(&req, &mut request_body)
            .await
            .unwrap();
        let graphql_request = graphql_request.0;
        Ok(self
            .schema
            .execute((self.request_transformer.clone())(req, graphql_request))
            .await
            .into())
    }
}