use axum::{Router, middleware};
use tower_http::normalize_path::NormalizePathLayer;
use crate::APIRouter;
use crate::middleware::log_request;
use crate::RouteConfig;
use crate::error::{Error, Result};
use std::net::SocketAddr;
use tracing::info;
use super::builder::APIApp;
impl<S> APIApp<S>
where
S: Clone + Send + Sync + 'static,
{
pub async fn run(self) -> Result<()> {
tracing_subscriber::fmt().with_target(false).init();
let openapi_json = self.generate_openapi_str();
let openapi_path = self.openapi_path.clone();
let docs_path = self.docs_path.clone();
let swagger_html = Self::swagger_html(&openapi_path);
let host = self.host.clone().unwrap_or_else(|| "127.0.0.1".to_owned());
let port = self.port.unwrap_or(6969);
let addr: SocketAddr = format!("{}:{}", host, port)
.parse()
.map_err(|e: std::net::AddrParseError| Error::AddressError(e.to_string()))?;
let openapi_handler = move |axum::extract::State(_): axum::extract::State<S>| async move {
(
[(axum::http::header::CONTENT_TYPE, "application/json")],
openapi_json
)
};
let docs_handler = move |axum::extract::State(_): axum::extract::State<S>| async move {
(
[(axum::http::header::CONTENT_TYPE, "text/html")],
swagger_html
)
};
let mut axum_router: Router<S> = Router::new();
for api_router in self.routers {
for route in api_router.routes {
axum_router = axum_router.route(&route.path, route.handler);
info!("Registering: {} {}", route.method, route.path);
}
}
let mut internal_router = APIRouter::new("");
internal_router.get(
&openapi_path,
openapi_handler,
RouteConfig::default().summary("OpenAPI JSON Specification")
);
internal_router.get(
&docs_path,
docs_handler,
RouteConfig::default().summary("Swagger UI Documentation")
);
for route in internal_router.routes {
axum_router = axum_router.route(&route.path, route.handler);
}
let axum_router = axum_router
.layer(middleware::from_fn(log_request))
.layer(NormalizePathLayer::trim_trailing_slash())
.with_state(self.state);
let listener = tokio::net::TcpListener::bind(addr)
.await
.map_err(|e| Error::BindError(e.to_string()))?;
info!("Server listening on http://{}", addr);
info!("Swagger UI available at http://{}{}", addr, docs_path);
axum::serve(listener, axum_router)
.await
.map_err(|e| Error::BindError(e.to_string()))?;
Ok(())
}
}