feat: update dependencies and enhance configuration loading for CORS support
This commit is contained in:
@@ -13,21 +13,22 @@ sqlite = [
|
||||
postgres = [
|
||||
"infra/postgres",
|
||||
"tower-sessions-sqlx-store/postgres",
|
||||
"k-core/postgres",
|
||||
]
|
||||
broker-nats = ["infra/broker-nats"]
|
||||
|
||||
[dependencies]
|
||||
k-core = { git = "https://git.gabrielkaszewski.dev/GKaszewski/k-core", features = [
|
||||
"logging",
|
||||
"db-sqlx",
|
||||
"sqlite",
|
||||
"http",
|
||||
"auth","sessions-db"
|
||||
] }
|
||||
domain = { path = "../domain" }
|
||||
infra = { path = "../infra", default-features = false, features = [
|
||||
"sqlite",
|
||||
] }
|
||||
|
||||
# Web framework
|
||||
#Web framework
|
||||
axum = { version = "0.8.8", features = ["macros"] }
|
||||
tower = "0.5.2"
|
||||
tower-http = { version = "0.6.2", features = ["cors", "trace"] }
|
||||
@@ -62,8 +63,6 @@ uuid = { version = "1.19.0", features = ["v4", "serde"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }
|
||||
|
||||
# Database
|
||||
dotenvy = "0.15.7"
|
||||
config = "0.15.19"
|
||||
|
||||
# Configuration
|
||||
config = "0.15.9"
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
//!
|
||||
//! Loads configuration from environment variables.
|
||||
|
||||
use std::env;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Config {
|
||||
pub database_url: String,
|
||||
pub session_secret: String,
|
||||
pub cors_allowed_origins: Vec<String>,
|
||||
|
||||
#[serde(default = "default_port")]
|
||||
pub port: u16,
|
||||
@@ -32,4 +35,39 @@ impl Config {
|
||||
.build()?
|
||||
.try_deserialize()
|
||||
}
|
||||
|
||||
pub fn from_env() -> Self {
|
||||
// Load .env file if it exists, ignore errors if it doesn't
|
||||
let _ = dotenvy::dotenv();
|
||||
|
||||
let host = env::var("HOST").unwrap_or_else(|_| "127.0.0.1".to_string());
|
||||
let port = env::var("PORT")
|
||||
.ok()
|
||||
.and_then(|p| p.parse().ok())
|
||||
.unwrap_or(3000);
|
||||
|
||||
let database_url =
|
||||
env::var("DATABASE_URL").unwrap_or_else(|_| "sqlite:data.db?mode=rwc".to_string());
|
||||
|
||||
let session_secret = env::var("SESSION_SECRET").unwrap_or_else(|_| {
|
||||
"k-notes-super-secret-key-must-be-at-least-64-bytes-long!!!!".to_string()
|
||||
});
|
||||
|
||||
let cors_origins_str = env::var("CORS_ALLOWED_ORIGINS")
|
||||
.unwrap_or_else(|_| "http://localhost:5173".to_string());
|
||||
|
||||
let cors_allowed_origins = cors_origins_str
|
||||
.split(',')
|
||||
.map(|s| s.trim().to_string())
|
||||
.filter(|s| !s.is_empty())
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
host,
|
||||
port,
|
||||
database_url,
|
||||
session_secret,
|
||||
cors_allowed_origins,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
use std::net::SocketAddr;
|
||||
use std::time::Duration as StdDuration;
|
||||
|
||||
use axum::Router;
|
||||
use domain::UserService;
|
||||
use infra::factory::build_session_store;
|
||||
use infra::factory::build_user_repository;
|
||||
use infra::run_migrations;
|
||||
use k_core::http::server::ServerConfig;
|
||||
use k_core::http::server::apply_standard_middleware;
|
||||
use k_core::logging;
|
||||
use time::Duration;
|
||||
use tokio::net::TcpListener;
|
||||
use tower_sessions::{Expiry, SessionManagerLayer};
|
||||
use tracing::info;
|
||||
@@ -16,6 +21,7 @@ mod error;
|
||||
mod routes;
|
||||
mod state;
|
||||
|
||||
use crate::auth::setup_auth_layer;
|
||||
use crate::config::Config;
|
||||
use crate::state::AppState;
|
||||
|
||||
@@ -23,38 +29,61 @@ use crate::state::AppState;
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
logging::init("api");
|
||||
|
||||
dotenvy::dotenv().ok();
|
||||
let config = Config::new().expect("Failed to load configuration");
|
||||
let config = Config::from_env();
|
||||
|
||||
info!("Starting server on {}:{}", config.host, config.port);
|
||||
|
||||
// Setup database
|
||||
tracing::info!("Connecting to database: {}", config.database_url);
|
||||
let db_config = k_core::db::DatabaseConfig {
|
||||
url: config.database_url.clone(),
|
||||
max_connections: 5,
|
||||
min_connections: 1,
|
||||
acquire_timeout: StdDuration::from_secs(30),
|
||||
};
|
||||
|
||||
let db_pool = k_core::db::connect(&db_config).await?;
|
||||
|
||||
infra::db::run_migrations(&db_pool).await?;
|
||||
run_migrations(&db_pool).await?;
|
||||
|
||||
let user_repo = build_user_repository(&db_pool).await?;
|
||||
let user_service = UserService::new(user_repo.clone());
|
||||
|
||||
let session_store = build_session_store(&db_pool).await?;
|
||||
|
||||
let session_layer = SessionManagerLayer::new(session_store)
|
||||
.with_secure(false) // Set to true in production with HTTPS
|
||||
.with_expiry(Expiry::OnInactivity(time::Duration::hours(1)));
|
||||
|
||||
let auth_layer = auth::setup_auth_layer(session_layer, user_repo.clone()).await?;
|
||||
|
||||
let state = AppState::new(user_service, config.clone());
|
||||
|
||||
let app = routes::api_v1_router().layer(auth_layer).with_state(state);
|
||||
let session_store = build_session_store(&db_pool)
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!(e))?;
|
||||
session_store
|
||||
.migrate()
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!(e))?;
|
||||
|
||||
let session_layer = SessionManagerLayer::new(session_store)
|
||||
.with_secure(false) // Set to true in prod
|
||||
.with_expiry(Expiry::OnInactivity(Duration::days(7)));
|
||||
|
||||
let auth_layer = setup_auth_layer(session_layer, user_repo).await?;
|
||||
|
||||
let server_config = ServerConfig {
|
||||
cors_origins: config.cors_allowed_origins.clone(),
|
||||
session_secret: Some(config.session_secret.clone()),
|
||||
};
|
||||
|
||||
let app = Router::new()
|
||||
.nest("/api/v1", routes::api_v1_router())
|
||||
.layer(auth_layer)
|
||||
.with_state(state);
|
||||
|
||||
let app = apply_standard_middleware(app, &server_config);
|
||||
|
||||
let addr: SocketAddr = format!("{}:{}", config.host, config.port).parse()?;
|
||||
let listener = TcpListener::bind(addr).await?;
|
||||
|
||||
tracing::info!("🚀 API server running at http://{}", addr);
|
||||
tracing::info!("🔒 Authentication enabled (axum-login)");
|
||||
tracing::info!("📝 API endpoints available at /api/v1/...");
|
||||
|
||||
axum::serve(listener, app).await?;
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user