1pub mod schema;
6pub mod resolver;
7pub mod context;
8
9pub use schema::GraphQLSchema;
10pub use context::Context;
11
12use oxidite_core::{Router, Result};
13use juniper::RootNode;
14use http_body_util::BodyExt;
15
16pub struct GraphQLHandler {
18 schema: std::sync::Arc<RootNode<'static, schema::QueryRoot, schema::MutationRoot, juniper::EmptySubscription<Context>>>,
19}
20
21impl GraphQLHandler {
22 pub fn new(schema: RootNode<'static, schema::QueryRoot, schema::MutationRoot, juniper::EmptySubscription<Context>>) -> Self {
23 Self {
24 schema: std::sync::Arc::new(schema),
25 }
26 }
27
28 pub fn mount(&self, router: &mut Router) -> Result<()> {
30 let schema = self.schema.clone();
31
32 router.post("/graphql", move |req: oxidite_core::OxiditeRequest| {
34 let schema = schema.clone();
35 async move {
36 let body_bytes = req.into_body()
38 .collect()
39 .await
40 .map_err(|e| oxidite_core::Error::BadRequest(format!("Failed to read body: {}", e)))?
41 .to_bytes();
42
43 let graphql_request: juniper::http::GraphQLRequest = serde_json::from_slice(&body_bytes)
45 .map_err(|e| oxidite_core::Error::BadRequest(format!("Invalid GraphQL request: {}", e)))?;
46
47 let context = Context::new();
49
50 let response = graphql_request.execute_sync(&schema, &context);
52
53 Ok(oxidite_core::OxiditeResponse::json(response))
55 }
56 });
57
58 let schema_clone = self.schema.clone();
60 router.get("/graphql", move |_req: oxidite_core::OxiditeRequest| {
61 async move {
62 let html = r#"<!DOCTYPE html>
63<html lang="en">
64<head>
65 <meta charset="UTF-8">
66 <meta name="viewport" content="width=device-width, initial-scale=1.0">
67 <title>GraphQL Playground</title>
68 <style>
69 body { margin: 0; padding: 0; font-family: Arial, sans-serif; }
70 #playground { height: 100vh; }
71 </style>
72 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/graphql-playground-react/build/static/css/index.css" />
73</head>
74<body>
75 <div id="playground"></div>
76 <script src="https://cdn.jsdelivr.net/npm/graphql-playground-react/build/static/js/middleware.js"></script>
77 <script>
78 GraphQLPlayground.init(document.getElementById('playground'), {
79 endpoint: '/graphql'
80 })
81 </script>
82</body>
83</html>"#;
84 Ok(oxidite_core::OxiditeResponse::html(html))
85 }
86 });
87
88 Ok(())
89 }
90}
91
92pub fn create_handler() -> GraphQLHandler {
94 GraphQLHandler::new(schema::create_schema())
95}
96