ferrox_graphql/lib.rs
1//! # Ferrox GraphQL (`ferrox-graphql`)
2//!
3//! `ferrox-graphql` integrates `async-graphql` into the Ferrox framework, allowing developers to quickly build, serve,
4//! and inspect GraphQL schemas alongside HTTP REST endpoints.
5//!
6//! ## Architectural Context
7//! Modern backend architectures often serve mobile applications or frontend dashboards that demand precise data fetching.
8//! `ferrox-graphql` provides high-performance GraphQL schema execution with built-in support for GraphQL Playground
9//! and automatic Schema Definition Language (SDL) export.
10//!
11//! ## Key Features
12//! - ⚡ **`async-graphql` Integration**: Full support for Queries, Mutations, and Subscriptions.
13//! - 🎮 **Interactive Playground**: Built-in IDE route for testing queries in development.
14//! - 📜 **SDL Export**: Programmatically generate `.graphql` schema files for client codegen.
15
16use async_graphql::{EmptyMutation, EmptySubscription, Object, Schema};
17use std::sync::Arc;
18
19/// A simple GraphQL Query root for demonstration.
20/// In a real scenario, this would be constructed dynamically or composed of multiple Query roots.
21pub struct QueryRoot;
22
23#[Object]
24impl QueryRoot {
25 /// A simple health check query
26 async fn ping(&self) -> &'static str {
27 "pong"
28 }
29}
30
31/// Helper to build a basic Ferrox GraphQL schema without mutations or subscriptions
32pub fn build_schema() -> Schema<QueryRoot, EmptyMutation, EmptySubscription> {
33 Schema::build(QueryRoot, EmptyMutation, EmptySubscription).finish()
34}
35
36/// Helper to build a GraphQL schema with a Repository injected into its context
37pub fn build_schema_with_context<T: Send + Sync + 'static>(
38 repo: Arc<T>,
39) -> Schema<QueryRoot, EmptyMutation, EmptySubscription> {
40 Schema::build(QueryRoot, EmptyMutation, EmptySubscription)
41 .data(repo)
42 .finish()
43}
44
45/// Helper to export the GraphQL Schema (SDL) to a file for Frontend Code Generation
46pub fn export_sdl<Q, M, S>(schema: &Schema<Q, M, S>, path: &str) -> Result<(), std::io::Error>
47where
48 Q: async_graphql::ObjectType + 'static,
49 M: async_graphql::ObjectType + 'static,
50 S: async_graphql::SubscriptionType + 'static,
51{
52 let sdl = schema.sdl();
53 std::fs::write(path, sdl)?;
54 println!("✅ GraphQL Schema successfully exported to {}", path);
55 Ok(())
56}
57
58pub fn setup() {
59 println!("ferrox-graphql initialized: Provides async-graphql Schema builders.");
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65 use async_graphql::value;
66 use serde_json::json;
67
68 // TDD: Verify that we can build a schema and execute a query without any reflection overhead
69 #[tokio::test]
70 async fn test_graphql_ping_query() {
71 let schema = build_schema();
72
73 let request = "{ ping }";
74 let response = schema.execute(request).await;
75
76 assert_eq!(
77 response.data.into_json().unwrap(),
78 json!({
79 "ping": "pong"
80 })
81 );
82 }
83}