tinycongress_api/
graphql.rs

1use crate::build_info::{BuildInfo as BuildInfoObject, BuildInfoProvider};
2use async_graphql::http::{playground_source, GraphQLPlaygroundConfig};
3use async_graphql::{Context, EmptySubscription, Object, Result, Schema};
4use async_graphql_axum::{GraphQLRequest, GraphQLResponse};
5use axum::extract::Extension;
6use axum::response::{Html, IntoResponse};
7
8/// The schema type with Query and Mutation roots
9pub type ApiSchema = Schema<QueryRoot, MutationRoot, EmptySubscription>;
10
11/// Query root for the GraphQL API
12pub struct QueryRoot;
13
14#[Object]
15impl QueryRoot {
16    /// Returns build metadata for the running service
17    #[allow(clippy::unused_async)]
18    async fn build_info(&self, ctx: &Context<'_>) -> Result<BuildInfoObject> {
19        let provider = ctx.data::<BuildInfoProvider>()?;
20        Ok(provider.build_info())
21    }
22}
23
24/// Mutation root for the GraphQL API
25pub struct MutationRoot;
26
27#[Object]
28impl MutationRoot {
29    /// Placeholder mutation - returns the input string
30    ///
31    /// This exists because GraphQL requires at least one mutation.
32    /// Replace with actual mutations as features are implemented.
33    #[allow(clippy::unused_async)]
34    async fn echo(&self, _ctx: &Context<'_>, message: String) -> String {
35        message
36    }
37}
38
39/// GraphQL playground handler - serves the interactive GraphQL IDE
40#[allow(clippy::unused_async)]
41pub async fn graphql_playground() -> impl IntoResponse {
42    Html(playground_source(GraphQLPlaygroundConfig::new("/graphql")))
43}
44
45/// GraphQL request handler - executes GraphQL queries and mutations
46pub async fn graphql_handler(schema: Extension<ApiSchema>, req: GraphQLRequest) -> GraphQLResponse {
47    schema.execute(req.into_inner()).await.into()
48}