From bdafb04ae1db57412c8f9fa8afb1e5627c60cb16 Mon Sep 17 00:00:00 2001 From: Toby Vincent Date: Fri, 12 Apr 2024 20:32:51 -0500 Subject: refactor: clean up fallback routes and routers --- ...01105cc9911eeca7ee3604c61fe56490e3e1ca8c78.json | 44 +++++++++++++++++++++ ...43873569e262a433618fd51007d6235b628da2690c.json | 46 ++++++++++++++++++++++ src/api.rs | 26 +++++++++++- src/api/error.rs | 5 ++- src/auth.rs | 6 +-- src/error.rs | 6 --- src/lib.rs | 36 +---------------- 7 files changed, 122 insertions(+), 47 deletions(-) create mode 100644 .sqlx/query-394ad01ebe1fe145ab22a401105cc9911eeca7ee3604c61fe56490e3e1ca8c78.json create mode 100644 .sqlx/query-bc6278e6e69a7e6780eccd43873569e262a433618fd51007d6235b628da2690c.json diff --git a/.sqlx/query-394ad01ebe1fe145ab22a401105cc9911eeca7ee3604c61fe56490e3e1ca8c78.json b/.sqlx/query-394ad01ebe1fe145ab22a401105cc9911eeca7ee3604c61fe56490e3e1ca8c78.json new file mode 100644 index 0000000..8062551 --- /dev/null +++ b/.sqlx/query-394ad01ebe1fe145ab22a401105cc9911eeca7ee3604c61fe56490e3e1ca8c78.json @@ -0,0 +1,44 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT * FROM user_ LIMIT 100", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "name", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 4, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false + ] + }, + "hash": "394ad01ebe1fe145ab22a401105cc9911eeca7ee3604c61fe56490e3e1ca8c78" +} diff --git a/.sqlx/query-bc6278e6e69a7e6780eccd43873569e262a433618fd51007d6235b628da2690c.json b/.sqlx/query-bc6278e6e69a7e6780eccd43873569e262a433618fd51007d6235b628da2690c.json new file mode 100644 index 0000000..357f2ee --- /dev/null +++ b/.sqlx/query-bc6278e6e69a7e6780eccd43873569e262a433618fd51007d6235b628da2690c.json @@ -0,0 +1,46 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT * FROM user_ WHERE name = $1 LIMIT 100", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "name", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 4, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false + ] + }, + "hash": "bc6278e6e69a7e6780eccd43873569e262a433618fd51007d6235b628da2690c" +} diff --git a/src/api.rs b/src/api.rs index 17cbd03..c776945 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,20 +1,25 @@ -use axum::{response::IntoResponse, routing::get}; +use axum::{http::Uri, response::IntoResponse, routing::get}; use crate::state::AppState; pub mod error; -mod users; +pub mod users; pub fn router() -> axum::Router { axum::Router::new() .merge(users::router()) .route("/healthcheck", get(healthcheck)) + .fallback(fallback) } pub async fn healthcheck() -> impl IntoResponse { "success" } +pub async fn fallback(uri: Uri) -> impl IntoResponse { + self::error::Error::RouteNotFound(uri) +} + #[cfg(test)] mod tests { use crate::tests::{setup_test_env, TestResult}; @@ -43,4 +48,21 @@ mod tests { Ok(()) } + + #[sqlx::test] + async fn test_fallback_not_found(pool: PgPool) -> TestResult { + setup_test_env(); + + let router = Router::new().merge(router()).with_state(AppState { pool }); + + let request = Request::builder() + .uri("/does-not-exist") + .body(Body::empty())?; + + let response = router.oneshot(request).await?; + + assert_eq!(StatusCode::NOT_FOUND, response.status()); + + Ok(()) + } } diff --git a/src/api/error.rs b/src/api/error.rs index f5d4291..bd43ce3 100644 --- a/src/api/error.rs +++ b/src/api/error.rs @@ -3,6 +3,9 @@ pub enum Error { #[error("Database error: {0}")] Sqlx(#[from] sqlx::Error), + #[error("Route not found: {0}")] + RouteNotFound(axum::http::Uri), + #[error("User not found")] UserNotFound, @@ -27,7 +30,7 @@ impl axum::response::IntoResponse for Error { use axum::http::StatusCode; let status = match self { - Self::UserNotFound => StatusCode::NOT_FOUND, + Self::RouteNotFound(_) | Self::UserNotFound => StatusCode::NOT_FOUND, Self::EmailExists => StatusCode::CONFLICT, Self::EmailInvalid(_) => StatusCode::UNPROCESSABLE_ENTITY, Self::InvalidToken => StatusCode::UNAUTHORIZED, diff --git a/src/auth.rs b/src/auth.rs index 8756291..0541b8e 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -2,7 +2,7 @@ use argon2::{ password_hash::{rand_core::OsRng, SaltString}, Argon2, PasswordHash, PasswordHasher, PasswordVerifier, }; -use axum::{extract::State, http::StatusCode}; +use axum::{extract::State, http::StatusCode, Router}; use axum_extra::{ headers::{authorization::Basic, Authorization}, routing::Resource, @@ -20,8 +20,8 @@ pub mod claims; pub mod error; pub mod jwt; -pub fn router() -> Resource { - Resource::named("auth").index(issue).create(create) +pub fn router() -> Router { + axum::Router::new().merge(Resource::named("users").index(issue).create(create)) } pub async fn issue( diff --git a/src/error.rs b/src/error.rs index c9fae0f..89fad78 100644 --- a/src/error.rs +++ b/src/error.rs @@ -11,9 +11,6 @@ pub enum Error { #[error("Migration error: {0}")] Migration(#[from] sqlx::migrate::MigrateError), - #[error("Route not found: {0}")] - RouteNotFound(axum::http::Uri), - #[error("API error: {0}")] Api(#[from] crate::api::error::Error), @@ -29,9 +26,6 @@ impl axum::response::IntoResponse for Error { match self { Self::Api(err) => err.into_response(), Self::Auth(err) => err.into_response(), - err @ Self::RouteNotFound(_) => { - (StatusCode::NOT_FOUND, err.to_string()).into_response() - } err => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response(), } } diff --git a/src/lib.rs b/src/lib.rs index 2afed5e..230336f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,3 @@ -use axum::{http::Uri, response::IntoResponse}; use tower_http::{cors::CorsLayer, trace::TraceLayer}; pub use error::{Error, Result}; @@ -12,32 +11,16 @@ pub mod utils; pub fn router() -> axum::Router { axum::Router::new() .nest("/api", api::router()) - .merge(auth::router()) - .fallback(fallback) + .nest("/auth", auth::router()) // TODO: do this correctly! .layer(CorsLayer::permissive()) .layer(TraceLayer::new_for_http()) } -pub async fn fallback(uri: Uri) -> impl IntoResponse { - Error::RouteNotFound(uri) -} - #[cfg(test)] pub(crate) mod tests { - use crate::state::AppState; - - use super::*; - use std::sync::Once; - use axum::{ - body::Body, - http::{Request, StatusCode}, - Router, - }; - use sqlx::PgPool; - use tower::ServiceExt; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; pub type TestResult> = std::result::Result; @@ -56,21 +39,4 @@ pub(crate) mod tests { std::env::set_var("JWT_SECRET", JWT_SECRET); }); } - - #[sqlx::test] - async fn test_fallback_not_found(pool: PgPool) -> TestResult { - setup_test_env(); - - let router = Router::new().merge(router()).with_state(AppState { pool }); - - let request = Request::builder() - .uri("/does-not-exist") - .body(Body::empty())?; - - let response = router.oneshot(request).await?; - - assert_eq!(StatusCode::NOT_FOUND, response.status()); - - Ok(()) - } } -- cgit v1.2.3-70-g09d2