feat(backend): ayarlar, MongoDB bağlantısı, Türkçe hata yapısı ve DB'li health check
- config.rs: ortam değişkenleri ve doğrulama - db.rs: bağlantı + ping (5 sn zaman aşımı) - error.rs: AppError → Türkçe JSON hata yanıtı - /api/health: veritabanına erişilemezse 503 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+53
-18
@@ -1,11 +1,18 @@
|
||||
use std::net::SocketAddr;
|
||||
mod config;
|
||||
mod db;
|
||||
#[allow(dead_code)] // AppError, Faz 1 – Adım 3 itibarıyla route'larda kullanılacak
|
||||
mod error;
|
||||
mod routes;
|
||||
mod state;
|
||||
|
||||
use std::{net::SocketAddr, process::ExitCode, sync::Arc};
|
||||
|
||||
use axum::{Json, Router, routing::get};
|
||||
use serde_json::{Value, json};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
use crate::{config::Config, state::AppState};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
async fn main() -> ExitCode {
|
||||
// .env dosyasını yükle (proje kökünde; üst klasörler de aranır). Yoksa sorun değil.
|
||||
dotenvy::dotenv().ok();
|
||||
|
||||
@@ -15,22 +22,50 @@ async fn main() {
|
||||
)
|
||||
.init();
|
||||
|
||||
let port: u16 = std::env::var("PORT")
|
||||
.ok()
|
||||
.and_then(|p| p.parse().ok())
|
||||
.unwrap_or(8080);
|
||||
let config = match Config::from_env() {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
tracing::error!("Ayar hatası: {e}");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
let app = Router::new().route("/api/health", get(health));
|
||||
let db = match db::connect(&config.mongodb_uri).await {
|
||||
Ok(db) => {
|
||||
tracing::info!("MongoDB bağlantısı kuruldu (veritabanı: {})", db.name());
|
||||
db
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
"MongoDB'ye bağlanılamadı. MONGODB_URI doğru mu, veritabanı çalışıyor mu? \
|
||||
(yerelde: npm run db:up)\nDetay: {e}"
|
||||
);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
let port = config.port;
|
||||
let state = AppState {
|
||||
db,
|
||||
config: Arc::new(config),
|
||||
};
|
||||
let app = routes::router(state);
|
||||
|
||||
let addr = SocketAddr::from(([0, 0, 0, 0], port));
|
||||
let listener = tokio::net::TcpListener::bind(addr)
|
||||
.await
|
||||
.expect("Port dinlenemedi");
|
||||
tracing::info!("Kakeibo API çalışıyor: http://localhost:{port}");
|
||||
axum::serve(listener, app).await.expect("Sunucu hatası");
|
||||
}
|
||||
let listener = match tokio::net::TcpListener::bind(addr).await {
|
||||
Ok(l) => l,
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
"{port} portu dinlenemedi (başka bir uygulama kullanıyor olabilir): {e}"
|
||||
);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
/// Sağlık kontrolü. Faz 1'de veritabanı durumu da eklenecek.
|
||||
async fn health() -> Json<Value> {
|
||||
Json(json!({ "status": "ok", "version": env!("CARGO_PKG_VERSION") }))
|
||||
tracing::info!("Kakeibo API çalışıyor: http://localhost:{port}");
|
||||
if let Err(e) = axum::serve(listener, app).await {
|
||||
tracing::error!("Sunucu hatası: {e}");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user