|
1 | 1 | use std::net::{IpAddr, Ipv4Addr, SocketAddr}; |
| 2 | +use std::sync::Arc; |
| 3 | + |
| 4 | +use axum::{Json, middleware::from_fn, routing::get}; |
| 5 | +use shield::{Shield, ShieldOptions}; |
| 6 | +use shield_axum::{AuthRoutes, ShieldLayer, auth_required}; |
| 7 | +use shield_memory::{MemoryStorage, User}; |
| 8 | +use shield_oidc::{Keycloak, OidcMethod}; |
| 9 | +use time::Duration; |
| 10 | +use tokio::net::TcpListener; |
| 11 | +use tower_sessions::{Expiry, MemoryStore, SessionManagerLayer}; |
| 12 | +use tracing::{info, level_filters::LevelFilter}; |
| 13 | +use utoipa_axum::router::OpenApiRouter; |
| 14 | +use utoipa_scalar::{Scalar, Servable}; |
2 | 15 |
|
3 | 16 | #[tokio::main] |
4 | 17 | async fn main() { |
5 | | - use std::sync::Arc; |
6 | | - |
7 | | - use axum::{Router, middleware::from_fn, routing::get}; |
8 | | - |
9 | | - use shield::{Shield, ShieldOptions}; |
10 | | - use shield_axum::{AuthRoutes, ShieldLayer, auth_required}; |
11 | | - use shield_memory::{MemoryStorage, User}; |
12 | | - use shield_oidc::{Keycloak, OidcMethod}; |
13 | | - use time::Duration; |
14 | | - use tokio::net::TcpListener; |
15 | | - use tower_sessions::{Expiry, MemoryStore, SessionManagerLayer}; |
16 | | - use tracing::{info, level_filters::LevelFilter}; |
17 | | - use utoipa::OpenApi; |
18 | | - use utoipa_swagger_ui::SwaggerUi; |
19 | | - |
20 | 18 | // Initialize tracing |
21 | 19 | tracing_subscriber::fmt() |
22 | 20 | .with_max_level(LevelFilter::DEBUG) |
@@ -52,21 +50,23 @@ async fn main() { |
52 | 50 | ); |
53 | 51 | let shield_layer = ShieldLayer::new(shield.clone()); |
54 | 52 |
|
55 | | - // Initialize OpenAPI specification (optional) |
56 | | - #[derive(OpenApi)] |
57 | | - #[openapi(nest( |
58 | | - (path = "/api/auth", api = AuthRoutes, tags = ["auth"]), |
59 | | - ))] |
60 | | - struct Docs; |
| 53 | + // Initialize API router |
| 54 | + let api_router = OpenApiRouter::new() |
| 55 | + .route("/protected", get(async || "Protected")) |
| 56 | + .route_layer(from_fn(auth_required::<User>)) |
| 57 | + .nest("/auth", AuthRoutes::openapi_router::<User, ()>()); |
61 | 58 |
|
62 | 59 | // Initialize router |
63 | | - let router = Router::new() |
64 | | - .route("/api/protected", get(async || "Protected")) |
65 | | - .route_layer(from_fn(auth_required::<User>)) |
66 | | - .nest("/api/auth", AuthRoutes::router::<User, ()>()) |
67 | | - .merge(SwaggerUi::new("/api-docs").url("/api/openapi.json", Docs::openapi())) |
| 60 | + let (router, openapi) = OpenApiRouter::new() |
| 61 | + .nest("/api", api_router) |
68 | 62 | .layer(shield_layer) |
69 | | - .layer(session_layer); |
| 63 | + .layer(session_layer) |
| 64 | + .split_for_parts(); |
| 65 | + |
| 66 | + // Add Scalar and OpenAPI specification |
| 67 | + let router = router |
| 68 | + .merge(Scalar::with_url("/api/reference", openapi.clone())) |
| 69 | + .route("/api/openapi.json", get(|| async { Json(openapi) })); |
70 | 70 |
|
71 | 71 | // Start app |
72 | 72 | info!("listening on http://{}", &addr); |
|
0 commit comments