Skip to main content

shaperail_runtime/graphql/
handler.rs

1//! GraphQL HTTP handler and playground (M15).
2
3use std::sync::Arc;
4
5use actix_web::{web, HttpRequest, HttpResponse};
6use async_graphql_actix_web::{GraphQLRequest, GraphQLResponse};
7
8use super::dataloader::RelationLoader;
9use super::schema::{GqlContext, GraphQLSchema};
10use crate::auth::extractor::try_extract_auth;
11use crate::handlers::crud::AppState;
12
13/// POST /graphql handler. Expects schema and state in app_data; injects GqlContext
14/// (with auth user and DataLoader) into the request.
15pub async fn graphql_handler(
16    req: HttpRequest,
17    schema: web::Data<GraphQLSchema>,
18    state: web::Data<Arc<AppState>>,
19    request: GraphQLRequest,
20) -> GraphQLResponse {
21    let user = try_extract_auth(&req);
22    let loader = RelationLoader::new(state.get_ref().clone(), state.resources.clone());
23    let context = GqlContext {
24        state: state.get_ref().clone(),
25        resources: state.resources.clone(),
26        user,
27        loader,
28    };
29    let mut gql_req = request.into_inner();
30    gql_req = gql_req.data(context);
31    let response = schema.execute(gql_req).await;
32    response.into()
33}
34
35/// GET /graphql/playground — serves a minimal GraphQL Playground HTML page.
36pub async fn playground_handler() -> HttpResponse {
37    let html = r#"<!DOCTYPE html>
38<html>
39<head><title>GraphQL Playground</title></head>
40<body>
41  <h1>GraphQL Playground</h1>
42  <p>Endpoint: <code>POST /graphql</code></p>
43  <textarea id="query" rows="8" style="width:90%;display:block;margin:1em 0;">query { __typename }</textarea>
44  <button onclick="run()">Run</button>
45  <pre id="result"></pre>
46  <script>
47    async function run() {
48      const query = document.getElementById('query').value;
49      const res = await fetch('/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query }) });
50      const data = await res.json();
51      document.getElementById('result').textContent = JSON.stringify(data, null, 2);
52    }
53  </script>
54</body>
55</html>"#;
56    HttpResponse::Ok()
57        .content_type("text/html; charset=utf-8")
58        .body(html)
59}