From c669e49c617be2fa1daa65e1f4176bf700136b31 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Sat, 23 Mar 2024 15:18:06 +0200 Subject: [PATCH] finished chapter 3.7 --- Cargo.lock | 1 + Cargo.toml | 1 + src/lib.rs | 20 +++++++++++++++++- tests/health_check.rs | 49 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a89a2b0..24885c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1353,5 +1353,6 @@ version = "0.1.0" dependencies = [ "axum", "reqwest", + "serde", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index 274de99..3d4d20c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ name = "zero2prod" [dependencies] axum = "0.7" +serde = { version = "1", features = ["derive"] } tokio = { version = "1", features = ["full"] } [dev-dependencies] diff --git a/src/lib.rs b/src/lib.rs index 53882e5..0c3d70e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,18 @@ -use axum::{extract::Path, http::StatusCode, response::IntoResponse, routing::get, Router}; +use axum::{ + extract::Path, + http::StatusCode, + response::IntoResponse, + routing::{get, post}, + Form, Router, +}; +use serde::Deserialize; pub fn app() -> Router { Router::new() .route("/", get(root)) .route("/:name", get(greet)) .route("/health_check", get(health_check)) + .route("/subscribtions", post(subscribe)) } async fn root() -> impl IntoResponse { @@ -17,3 +25,13 @@ async fn greet(Path(name): Path) -> impl IntoResponse { async fn health_check() -> impl IntoResponse { StatusCode::OK } + +#[derive(Deserialize)] +struct FormData { + name: String, + email: String, +} + +async fn subscribe(Form(form): Form) -> impl IntoResponse { + StatusCode::OK +} diff --git a/tests/health_check.rs b/tests/health_check.rs index 00e46a9..0c03ae3 100644 --- a/tests/health_check.rs +++ b/tests/health_check.rs @@ -1,10 +1,11 @@ +use reqwest::Client; use tokio::net::TcpListener; #[tokio::test] async fn health_check() { let address = spawn_app().await; let url = format!("{}/health_check", &address); - let client = reqwest::Client::new(); + let client = Client::new(); let response = client .get(&url) .send() @@ -15,6 +16,52 @@ async fn health_check() { assert_eq!(Some(0), response.content_length()); } +#[tokio::test] +async fn subscribe_returns_200_for_valid_form_data() { + let address = spawn_app().await; + let client = Client::new(); + + let body = "name=kristofers%20solo&email=dev%40kristofers.solo"; + let response = client + .post(&format!("{}/subscribtions", &address)) + .header("Content-Type", "application/x-www-form-urlencoded") + .body(body) + .send() + .await + .expect("Failed to execute request."); + + assert_eq!(200, response.status().as_u16()); +} + +#[tokio::test] +async fn subscribe_returns_400_when_data_is_missing() { + let address = spawn_app().await; + let client = Client::new(); + + let test_cases = vec![ + ("name=krisotfers%20solo", "missing the email"), + ("email=dev%40kristofers.solo", "missing the name"), + ("", "missing both name and email"), + ]; + + for (invalid_body, error_message) in test_cases { + let response = client + .post(&format!("{}/subscribtions", &address)) + .header("Content-Type", "application/x-www-form-urlencoded") + .body(invalid_body) + .send() + .await + .expect("Failed to execute request."); + + assert_eq!( + 422, + response.status().as_u16(), + "The API did not call with 400 Bad Request when the payload was {}.", + error_message + ); + } +} + async fn spawn_app() -> String { let listener = TcpListener::bind("127.0.0.1:0") .await