dogy_backend_api/
main.rs

1//! Main entry point for the Dogy API server.
2//! This module sets up the server, database connection, and routes.
3use std::sync::Arc;
4use tracing::info;
5
6use axum::{middleware as mw, routing::get, Json, Router};
7use config::load_config;
8use middleware::log::layer::log_middleware;
9use serde_json::json;
10use service::api_v1_routes;
11use sqlx::{postgres::PgPoolOptions, PgPool};
12use tracing_subscriber::EnvFilter;
13
14pub use self::error::{Error, PayloadJson, Result};
15
16mod config;
17mod error;
18mod middleware;
19mod service;
20
21/// This is the application state that is shared across all axum handlers.
22///
23/// Remember to not put sensitive information (eg. env var), large objects (files/embedding), or
24/// request-specific data in here (auth bearer token).
25#[derive(Clone)]
26struct AppState {
27    /// Postgres Database connection pool. Be sure that the `DATABASE_URL` from Neon does not have
28    /// **Connection Pooling** enabled.
29    db: Arc<PgPool>,
30}
31
32/// Main function to start the server.
33///
34/// Tracing is initialized based on the build profile.
35/// `debug` for debug builds and `info` for release builds.
36/// For debug builds, the logs are printed in a human-readable format.
37/// For release builds, the logs are printed in a JSON format.
38///
39/// Config is also loaded from the `.env` file using [`load_config()`].
40#[tokio::main]
41pub async fn main() -> Result<()> {
42    #[cfg(debug_assertions)]
43    tracing_subscriber::fmt()
44        .with_target(false)
45        .with_env_filter(EnvFilter::new("debug"))
46        .init();
47
48    #[cfg(not(debug_assertions))]
49    tracing_subscriber::fmt()
50        .json()
51        .with_target(false)
52        .with_env_filter(EnvFilter::new("info"))
53        .init();
54
55    info!("Starting Server");
56
57    // Loads config from .env file.
58    let config = load_config();
59
60    info!("Connecting to database...");
61    let pool = PgPoolOptions::new()
62        .max_connections(10)
63        .connect(&config.DATABASE_URL)
64        .await
65        .expect("Failed to create PgPool.");
66    info!("Connected to database.");
67
68    //sqlx::migrate!("./migrations").run(&pool).await.unwrap();
69    //sqlx::migrate!("./migrations").undo(&pool, 1).await.unwrap();
70    let shared_state = AppState { db: Arc::new(pool) };
71
72    let app = Router::new()
73        .route(
74            "/",
75            get(|| async { Json(json!({ "message": "Welcome to Dogy API" })) }),
76        )
77        .nest("/api/v1", api_v1_routes(shared_state.clone()).await)
78        .layer(mw::map_response(log_middleware));
79
80    // run our app with hyper, listening globally on port 8080
81    let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", config.PORT))
82        .await
83        .unwrap();
84    axum::serve(listener, app).await.unwrap();
85
86    Ok(())
87}