mod dynamic_schema;
mod executor;
mod schema;
mod schema_generator; mod subscription_handler;
#[cfg(feature = "graphql")]
use crate::server::host::ServerHost;
#[cfg(feature = "graphql")]
use anyhow::Result;
#[cfg(feature = "graphql")]
use async_graphql::http::{GraphQLPlaygroundConfig, playground_source};
#[cfg(feature = "graphql")]
use axum::{
Router,
extract::{Extension, Json as AxumJson},
response::{Html, IntoResponse},
routing::{get, post},
};
#[cfg(feature = "graphql")]
use executor::GraphQLExecutor;
#[cfg(feature = "graphql")]
use serde::Deserialize;
#[cfg(feature = "graphql")]
use std::sync::Arc;
#[cfg(feature = "graphql")]
#[derive(Debug, Deserialize)]
struct GraphQLRequestBody {
query: String,
variables: Option<std::collections::HashMap<String, serde_json::Value>>,
#[allow(dead_code)]
operation_name: Option<String>,
}
#[cfg(feature = "graphql")]
pub struct GraphQLExposure;
#[cfg(feature = "graphql")]
impl GraphQLExposure {
pub fn build_router(host: Arc<ServerHost>) -> Result<Router> {
let mut router = Router::new()
.route("/graphql", post(graphql_handler_custom))
.route("/graphql/playground", get(graphql_playground))
.route("/graphql/schema", get(graphql_dynamic_schema));
if host.event_bus().is_some() || host.notification_store().is_some() {
router = router.route("/graphql/ws", get(subscription_handler::graphql_ws_handler));
}
let router = router.layer(Extension(host));
Ok(router)
}
}
#[cfg(feature = "graphql")]
async fn graphql_handler_custom(
Extension(host): Extension<Arc<ServerHost>>,
AxumJson(request): AxumJson<GraphQLRequestBody>,
) -> impl IntoResponse {
let executor = GraphQLExecutor::new(host).await;
match executor.execute(&request.query, request.variables).await {
Ok(response) => AxumJson(response),
Err(e) => AxumJson(serde_json::json!({
"errors": [{
"message": e.to_string()
}]
})),
}
}
#[cfg(feature = "graphql")]
async fn graphql_playground() -> impl IntoResponse {
Html(playground_source(GraphQLPlaygroundConfig::new("/graphql")))
}
#[cfg(feature = "graphql")]
async fn graphql_dynamic_schema(Extension(host): Extension<Arc<ServerHost>>) -> impl IntoResponse {
use schema_generator::SchemaGenerator;
let generator = SchemaGenerator::new(host);
let sdl = generator.generate_sdl().await;
(
[(
axum::http::header::CONTENT_TYPE,
"text/plain; charset=utf-8",
)],
sdl,
)
}
#[cfg(not(feature = "graphql"))]
mod graphql_placeholder {
use super::super::super::host::ServerHost;
use anyhow::Result;
use axum::Router;
pub struct GraphQLExposure;
impl GraphQLExposure {
pub fn build_router(_host: ServerHost) -> Result<Router> {
anyhow::bail!(
"GraphQL support is not enabled. Enable the 'graphql' feature to use GraphQL."
);
}
}
}