From b5c443506e9ac56625276767c9f4942c92d067fe Mon Sep 17 00:00:00 2001 From: azdle Date: Wed, 14 May 2025 13:57:31 -0500 Subject: [PATCH] add rough subscribe endpoint (3.7) --- src/server/routes/mod.rs | 5 ++- src/server/routes/subscriptions/mod.rs | 38 +++++++++++++++++++ tests/subscriptions.rs | 51 ++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/server/routes/subscriptions/mod.rs create mode 100644 tests/subscriptions.rs diff --git a/src/server/routes/mod.rs b/src/server/routes/mod.rs index 59746f1..e132a61 100644 --- a/src/server/routes/mod.rs +++ b/src/server/routes/mod.rs @@ -1,14 +1,15 @@ mod auth; +mod subscriptions; use axum::{routing::get, Router}; use super::AppState; pub fn build() -> Router { - let auth = auth::build(); Router::new() .route("/health", get(health_check)) - .nest("/auth", auth) + .nest("/auth", auth::build()) + .nest("/subscriptions", subscriptions::build()) } // just always returns a 200 OK for now, the server has no state, if it's up, it's working diff --git a/src/server/routes/subscriptions/mod.rs b/src/server/routes/subscriptions/mod.rs new file mode 100644 index 0000000..0331d7d --- /dev/null +++ b/src/server/routes/subscriptions/mod.rs @@ -0,0 +1,38 @@ +use axum::{http::StatusCode, response::IntoResponse, routing::post, Form, Router}; +use serde::Deserialize; +use tracing::info; + +use crate::server::AppState; + +pub fn build() -> Router { + Router::new().route("/", post(subscribe)) +} + +#[derive(Deserialize)] +pub struct SubscribeForm { + name: Option, + email: String, +} + +pub async fn subscribe(Form(form): Form) -> Result<(), SubscribeError> { + info!(form.name, form.email, "subscribe attempt"); + + if form.email.is_empty() { + return Err(SubscribeError::InvalidEmail); + } + + Ok(()) +} + +pub enum SubscribeError { + InvalidEmail, +} + +impl IntoResponse for SubscribeError { + fn into_response(self) -> axum::response::Response { + match self { + SubscribeError::InvalidEmail => (StatusCode::BAD_REQUEST, "Invalid Email Address"), + } + .into_response() + } +} diff --git a/tests/subscriptions.rs b/tests/subscriptions.rs new file mode 100644 index 0000000..6a1194b --- /dev/null +++ b/tests/subscriptions.rs @@ -0,0 +1,51 @@ +pub mod fixture; +use fixture::TestServer; + +use anyhow::Result; +use test_log::test as traced; + +#[traced(tokio::test)] +async fn subscribe_succeeds_with_valid_input() -> Result<()> { + let server = TestServer::spawn().await; + let client = reqwest::Client::builder().build()?; + + // Subscribe + let resp = client + .post(server.url("/subscriptions")) + .header("Content-Type", "application/x-www-form-urlencoded") + .body("name=le%20guin&email=ursula_le_guin%40gmail.com") + .send() + .await?; + + assert_eq!(resp.status(), 200, "subscribe succeeds"); + + server.shutdown().await +} + +#[traced(tokio::test)] +async fn subscribe_fails_with_missing_data() -> Result<()> { + let server = TestServer::spawn().await; + let client = reqwest::Client::new(); + + let test_cases = [ + ("", "missing both name and email"), + ("name=le%20guin", "missing the email"), + ]; + + for (body, msg) in test_cases { + let resp = client + .post(server.url("/subscriptions")) + .header("Content-Type", "application/x-www-form-urlencoded") + .body(body) + .send() + .await?; + + assert_eq!( + resp.status(), + 422, + "subscribe fails with bad request when {msg}" + ); + } + + server.shutdown().await +}