diff options
author | Toby Vincent <tobyv@tobyvin.dev> | 2024-04-02 19:07:23 -0500 |
---|---|---|
committer | Toby Vincent <tobyv@tobyvin.dev> | 2024-04-02 19:07:23 -0500 |
commit | 9034c74cd36cdf3615dd80dc975500d235cebfcc (patch) | |
tree | bc6cfdb3c70c790e45e36a1a3977cf88ce4337c2 /src/routes/user.rs | |
parent | d3a09372b5b945a609cce5e28c4d4233e3b134e8 (diff) |
refactor: move routes into individual modules
Diffstat (limited to 'src/routes/user.rs')
-rw-r--r-- | src/routes/user.rs | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/src/routes/user.rs b/src/routes/user.rs new file mode 100644 index 0000000..71ed9a0 --- /dev/null +++ b/src/routes/user.rs @@ -0,0 +1,106 @@ +use std::sync::Arc; + +use axum::{extract::State, response::IntoResponse, Json}; +use axum_extra::routing::TypedPath; +use serde::Deserialize; + +use crate::{model::User, state::AppState, Error}; + +#[derive(Debug, Deserialize, TypedPath)] +#[typed_path("/api/user/:uuid")] +pub struct UserUuid { + pub uuid: uuid::Uuid, +} + +impl UserUuid { + /// Get a user with a specific `uuid` + #[tracing::instrument] + pub async fn get(self, State(state): State<Arc<AppState>>) -> impl IntoResponse { + sqlx::query_as!(User, "SELECT * FROM users WHERE uuid = $1", self.uuid) + .fetch_optional(&state.pool) + .await? + .ok_or_else(|| Error::UserNotFound) + .map(Json) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use axum::{ + body::Body, + http::{Request, StatusCode}, + }; + use http_body_util::BodyExt; + use sqlx::PgPool; + use tower::ServiceExt; + + use crate::init_router; + + const JWT_SECRET: &str = "test-jwt-secret-token"; + const JWT_MAX_AGE: time::Duration = time::Duration::HOUR; + + #[sqlx::test] + async fn test_user_not_found(pool: PgPool) -> Result<(), Error> { + let state = Arc::new(AppState { + pool, + jwt_secret: JWT_SECRET.to_string(), + jwt_max_age: JWT_MAX_AGE, + }); + let router = init_router(state.clone()); + + let user = User { + uuid: uuid::uuid!("4c14f795-86f0-4361-a02f-0edb966fb145"), + name: "Arthur Dent".to_string(), + email: "adent@earth.sol".to_string(), + ..Default::default() + }; + + let request = Request::builder() + .uri(format!("/api/user/{}", user.uuid)) + .body(Body::empty())?; + + let response = router.oneshot(request).await.unwrap(); + + assert_eq!(StatusCode::NOT_FOUND, response.status()); + + Ok(()) + } + + #[sqlx::test(fixtures(path = "../../fixtures", scripts("users")))] + async fn test_user_ok(pool: PgPool) -> Result<(), Error> { + let state = Arc::new(AppState { + pool, + jwt_secret: JWT_SECRET.to_string(), + jwt_max_age: JWT_MAX_AGE, + }); + let router = init_router(state.clone()); + + let user = User { + uuid: uuid::uuid!("4c14f795-86f0-4361-a02f-0edb966fb145"), + name: "Arthur Dent".to_string(), + email: "adent@earth.sol".to_string(), + ..Default::default() + }; + + let request = Request::builder() + .uri(format!("/api/user/{}", user.uuid)) + .body(Body::empty())?; + + let response = router.oneshot(request).await.unwrap(); + + assert_eq!(StatusCode::OK, response.status()); + + let body_bytes = response.into_body().collect().await?.to_bytes(); + let User { + uuid, name, email, .. + } = serde_json::from_slice(&body_bytes)?; + + assert_eq!(user.uuid, uuid); + assert_eq!(user.name, name); + assert_eq!(user.email, email); + + Ok(()) + } +} |