fraiseql-server 2.8.0

HTTP server for FraiseQL v2 GraphQL engine
Documentation
//! Application router construction and route registration.
//!
//! Split into sub-modules by responsibility:
//! - [`state`]: `AppState` construction
//! - [`graphql`]: GraphQL endpoint with auth and compression
//! - [`admin`]: Base routes, studio, admin API, introspection, metrics, design audit
//! - [`auth`]: PKCE, social login, MFA, session identity, token revocation
//! - [`extensions`]: MCP, API routes, RBAC, observers, storage, functions, REST
//! - [`middleware`]: Tracing, CORS, body/header limits, timeout, rate limiting
//! - [`observers`]: Observer management routes

mod admin;
#[cfg(feature = "auth")]
mod auth;
mod extensions;
mod graphql;
mod middleware;
#[cfg(test)]
mod mount_authz_tests;
#[cfg(feature = "observers")]
pub(in crate::server) mod observers;
mod state;

use std::sync::Arc;

use axum::Router;
use fraiseql_core::{db::traits::DatabaseAdapter, security::OidcValidator};

use super::{OidcAuthState, Server};
use crate::routes::graphql::AppState;

impl<A: DatabaseAdapter + Clone + Send + Sync + 'static> Server<A> {
    /// Build an [`OidcAuthState`] for `validator`, attaching the configured
    /// token-revocation manager (if any) so revoked tokens are rejected on **every**
    /// authenticated route (H8).
    ///
    /// All OIDC middleware construction goes through this helper to keep revocation
    /// enforcement uniform: a bare `OidcAuthState::new` at a route would silently skip
    /// the revocation check for that route.
    pub(super) fn oidc_auth_state(&self, validator: Arc<OidcValidator>) -> OidcAuthState {
        OidcAuthState::new(validator).with_revocation(self.revocation_manager.clone())
    }

    /// Build application router and return the shared `AppState`.
    ///
    /// The returned `AppState` is needed by the lifecycle module for
    /// SIGUSR1 schema reload handling.
    pub(super) fn build_router(&self) -> (Router, AppState<A>) {
        let state = self.build_app_state();

        // Build GraphQL route (possibly with auth + Content-Type enforcement).
        let graphql_router = self.build_graphql_router(&state);

        // Mount base routes, studio, admin, introspection, metrics, design audit.
        let mut app = Router::new();
        app = self.mount_base_and_admin_routes(app.merge(graphql_router), &state);

        // Mount auth routes (PKCE, social, MFA, /auth/me, revocation).
        #[cfg(feature = "auth")]
        {
            app = self.mount_auth_routes(app);
        }

        // Mount extension routes (MCP, API, RBAC, storage, functions, REST, realtime).
        app = self.mount_extensions(app, &state);

        // Apply global middleware layers (metrics, tracing, CORS, limits, timeout, rate limiting).
        app = self.apply_middleware(app, &state);

        (app, state)
    }
}