qm_server/lib.rs
1#![deny(missing_docs)]
2
3//! Server configuration and utilities.
4//!
5//! This crate provides server configuration and GraphQL handler utilities
6//! for building microservices with Axum and async-graphql.
7//!
8//! ## Features
9//!
10//! - **GraphQL Handler**: Axum handler for async-graphql with auth injection
11//! - **Server Config**: Environment-based server configuration
12//! - **Auth Integration**: Automatic auth header processing
13//!
14//! ## Usage
15//!
16//! \```ignore
17//! use qm_server::{graphql_handler, ServerConfig};
18//!
19//! #[tokio::main]
20//! async fn main() -> anyhow::Result<()> {
21//! let config = ServerConfig::new()?;
22//! // Build and run Axum server with graphql_handler
23//! Ok(())
24//! }
25//! \```
26//!
27//! ## Environment Variables
28//!
29//! | Variable | Description | Default |
30//! |----------|-------------|---------|
31//! | `SERVER_HOST` | Server host | `127.0.0.1` |
32//! | `SERVER_PORT` | Server port | `3000` |
33//! | `SERVER_APP_NAME` | Application name | `quick-microservice` |
34
35use async_graphql_axum::{GraphQLRequest, GraphQLResponse};
36use axum::extract::Extension;
37use axum::http::header::HeaderMap;
38use axum::http::header::AUTHORIZATION;
39use qm_role::AuthContainer;
40
41mod config;
42pub use config::Config as ServerConfig;
43
44/// GraphQL request handler for Axum.
45///
46/// Extracts the Authorization header and injects it into the GraphQL request
47/// context. The schema extension type `A` is used for authentication.
48pub async fn graphql_handler<A, Q, M, S>(
49 schema: Extension<async_graphql::Schema<Q, M, S>>,
50 headers: HeaderMap,
51 req: GraphQLRequest,
52) -> GraphQLResponse
53where
54 A: Send + Sync + 'static,
55 Q: async_graphql::ObjectType + Send + Sync + 'static,
56 M: async_graphql::ObjectType + async_graphql::ContainerType + Send + Sync + 'static,
57 S: async_graphql::SubscriptionType + Send + Sync + 'static,
58{
59 let mut req = req.into_inner();
60 if let Some(auth_header) = headers.get(AUTHORIZATION).map(AuthContainer::<A>::from) {
61 req = req.data(auth_header);
62 } else {
63 req = req.data(AuthContainer::<A>::default());
64 }
65 schema.execute(req).await.into()
66}