Skip to main content

fraiseql_server/routes/api/
schema.rs

1//! Schema export API endpoints.
2//!
3//! Provides endpoints for:
4//! - Exporting compiled schema as GraphQL SDL (Schema Definition Language)
5//! - Exporting schema as JSON for programmatic access
6
7use axum::{
8    Json,
9    extract::State,
10    http::StatusCode,
11    response::{IntoResponse, Response},
12};
13use fraiseql_core::db::traits::DatabaseAdapter;
14use serde::Serialize;
15
16use crate::routes::{
17    api::types::{ApiError, ApiResponse},
18    graphql::AppState,
19};
20
21/// Response containing GraphQL SDL schema.
22#[derive(Debug, Serialize)]
23pub struct GraphQLSchemaResponse {
24    /// GraphQL Schema Definition Language (SDL) representation
25    pub schema: String,
26}
27
28/// Response containing JSON-formatted schema.
29#[derive(Debug, Serialize)]
30pub struct JsonSchemaResponse {
31    /// Compiled schema as JSON object
32    pub schema: serde_json::Value,
33}
34
35/// Export compiled schema as GraphQL SDL.
36///
37/// Returns the schema in GraphQL Schema Definition Language (SDL) format.
38/// This is human-readable and suitable for documentation, tools, and introspection.
39///
40/// Response format: `text/plain` (not JSON wrapped)
41///
42/// # Errors
43///
44/// This handler currently always succeeds; it is infallible.
45pub async fn export_sdl_handler<A: DatabaseAdapter>(
46    State(state): State<AppState<A>>,
47) -> Result<Response, ApiError> {
48    let schema_sdl = state.executor().schema().raw_schema();
49    Ok((StatusCode::OK, schema_sdl).into_response())
50}
51
52/// Export compiled schema as JSON.
53///
54/// Returns the full compiled schema in JSON format.
55/// This includes type information, field definitions, and metadata.
56/// Useful for programmatic access and tooling.
57///
58/// Response format: Standard JSON API response with data wrapper
59///
60/// # Errors
61///
62/// Returns `ApiError` with an internal error if the schema cannot be serialized to JSON.
63pub async fn export_json_handler<A: DatabaseAdapter>(
64    State(state): State<AppState<A>>,
65) -> Result<Json<ApiResponse<JsonSchemaResponse>>, ApiError> {
66    let schema_json = serde_json::to_value(state.executor().schema())
67        .map_err(|e| ApiError::internal_error(format!("Failed to serialize schema: {e}")))?;
68
69    let response = JsonSchemaResponse {
70        schema: schema_json,
71    };
72
73    Ok(Json(ApiResponse {
74        status: "success".to_string(),
75        data:   response,
76    }))
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn test_graphql_response_creation() {
85        let response = GraphQLSchemaResponse {
86            schema: "type Query { hello: String }".to_string(),
87        };
88
89        assert_eq!(response.schema, "type Query { hello: String }");
90    }
91
92    #[test]
93    fn test_json_response_creation() {
94        let response = JsonSchemaResponse {
95            schema: serde_json::json!({"types": []}),
96        };
97
98        assert!(response.schema.is_object());
99    }
100}