debt-pirate/api/src/requests/mod.rs

108 lines
2.7 KiB
Rust
Raw Normal View History

mod account;
mod auth;
mod user;
use std::{sync::mpsc::Sender, time::Duration};
use axum::{
extract::{MatchedPath, Request},
response::Response,
Router,
};
use humantime::format_duration;
use tokio::net::TcpListener;
use tower_http::trace::TraceLayer;
use tracing::{error, info, info_span, warn, Span};
2024-10-05 08:09:46 -04:00
use uuid::Uuid;
2024-08-24 13:22:51 -04:00
use crate::{
db::DbPool,
models::AppError,
services::{config::Config, CachePool, UserConfirmationMessage},
2024-08-24 13:22:51 -04:00
};
#[derive(Clone)]
pub struct AppState {
2024-10-05 08:09:46 -04:00
db_pool: DbPool,
cache_pool: CachePool,
config: Config,
mail_sender: Sender<UserConfirmationMessage>,
}
impl AppState {
pub fn new(
db_pool: DbPool,
cache_pool: CachePool,
config: Config,
mail_sender: Sender<UserConfirmationMessage>,
) -> Self {
2024-10-05 08:09:46 -04:00
Self {
db_pool,
cache_pool,
config,
mail_sender,
2024-10-05 08:09:46 -04:00
}
}
2024-10-05 08:09:46 -04:00
pub fn db_pool(&self) -> &DbPool {
&self.db_pool
}
pub fn cache_pool(&self) -> &CachePool {
&self.cache_pool
}
pub fn config(&self) -> &Config {
&self.config
}
pub fn mail_sender(&self) -> &Sender<UserConfirmationMessage> {
&self.mail_sender
}
}
2024-10-05 08:09:46 -04:00
pub async fn start_app(
db_pool: DbPool,
cache_pool: CachePool,
config: Config,
mail_sender: Sender<UserConfirmationMessage>,
2024-10-05 08:09:46 -04:00
) -> Result<(), AppError> {
let connection_uri = config.app_connection_uri();
info!("Listening on {connection_uri}...");
let listener = TcpListener::bind(connection_uri).await.unwrap();
let logging_layer = TraceLayer::new_for_http()
.make_span_with(|request: &Request| {
let path = request
.extensions()
.get::<MatchedPath>()
2024-10-03 15:27:30 -04:00
.map(MatchedPath::as_str).unwrap_or(request.uri().path());
2024-10-05 08:09:46 -04:00
info_span!("api_request", request_id = %Uuid::now_v7(), method = %request.method(), %path, status = tracing::field::Empty)
})
.on_response(|response: &Response, duration: Duration, span: &Span| {
let status = response.status();
span.record("status", status.to_string());
match status {
w if w.is_redirection() => warn!(duration = ?format_duration(duration).to_string()),
e if e.is_client_error() || e.is_server_error() => error!(duration = ?format_duration(duration).to_string()),
_ => info!(duration = ?format_duration(duration).to_string())
}
});
let state = AppState::new(db_pool, cache_pool, config, mail_sender);
let app = Router::new()
.merge(user::requests(state.clone()))
.merge(auth::requests(state.clone()))
.merge(account::requests(state.clone()))
.layer(logging_layer);
2024-09-30 00:15:19 -04:00
info!("API started successfully.");
axum::serve(listener, app)
.await
.map_err(AppError::app_startup)?;
Ok(())
}