summaryrefslogtreecommitdiffstats
path: root/src/routes.rs
blob: 0a81317d5375ebc1b0cd2b3bfd2c69c72dadca50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use std::sync::Arc;

use axum::{
    extract::State,
    http::{StatusCode, Uri},
    Json,
};
use axum_extra::routing::{RouterExt, TypedPath};
use serde::Deserialize;

use crate::{model::User, state::AppState, Error};

pub fn router(state: AppState) -> axum::Router {
    axum::Router::new()
        // .route("/api/user", get(get_user))
        .typed_get(HealthCheck::get)
        .typed_get(UserId::get)
        .fallback(fallback)
        .with_state(Arc::new(state))
}

#[derive(Debug, Deserialize, TypedPath)]
#[typed_path("/api/healthcheck")]
pub struct HealthCheck;

impl HealthCheck {
    pub async fn get(self) -> Json<serde_json::Value> {
        const MESSAGE: &str = "Unnamed server";

        let json_response = serde_json::json!({
            "status": "success",
            "message": MESSAGE
        });

        Json(json_response)
    }
}

#[derive(Debug, Deserialize, TypedPath)]
#[typed_path("/api/user/:uuid")]
pub struct UserId {
    pub uuid: uuid::Uuid,
}

impl UserId {
    /// Get a user via their `id`
    #[tracing::instrument(ret, skip(data))]
    pub async fn get(
        self,
        State(data): State<Arc<AppState>>,
    ) -> Result<Json<serde_json::Value>, Error> {
        sqlx::query_as!(User, "SELECT * FROM users WHERE id = $1", self.uuid)
            .fetch_optional(&data.db_pool)
            .await?
            .ok_or_else(|| Error::UserNotFound(self.uuid))
            .map(User::into_query_response)
    }
}

pub async fn fallback(uri: Uri) -> (StatusCode, String) {
    (StatusCode::NOT_FOUND, format!("Route not found: {uri}"))
}

#[cfg(test)]
mod tests {
    use super::*;

    use axum_test::TestServer;

    #[tokio::test]
    async fn test_fallback() -> Result<(), Box<dyn std::error::Error>> {
        let server = TestServer::new(axum::Router::new().fallback(fallback))?;

        let response = server.get("/fallback").await;

        assert_eq!(StatusCode::NOT_FOUND, response.status_code());

        Ok(())
    }
}