zero2prod_axum/src/routes/subscriptions.rs

89 lines
2.3 KiB
Rust
Raw Normal View History

2024-02-12 10:55:23 +01:00
use crate::domain::SubscriberEmail;
use crate::domain::{NewSubscriber, SubscriberName};
use axum::extract::State;
2024-01-01 21:02:31 +01:00
use axum::routing::post;
use axum::Form;
2023-12-30 22:21:57 +01:00
use axum::Router;
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
};
use chrono::Utc;
use serde::Deserialize;
use sqlx::PgPool;
use uuid::Uuid;
#[derive(Debug, Deserialize)]
struct FormData {
email: String,
name: String,
}
2024-02-04 13:48:31 +01:00
#[tracing::instrument(
name = "Adding a new subscriber",
skip(form, pool),
fields(
request_id = %Uuid::new_v4(),
subscriber_email = %form.email,
subscriber_name = %form.name
)
)]
pub async fn subscribe(State(pool): State<PgPool>, Form(form): Form<FormData>) -> Response {
2024-02-12 10:55:23 +01:00
let name = match SubscriberName::parse(form.name) {
Ok(name) => name,
Err(_) => {
return (StatusCode::BAD_REQUEST, "Invalid name").into_response();
}
};
let email = match SubscriberEmail::parse(form.email) {
Ok(email) => email,
Err(_) => {
return (StatusCode::BAD_REQUEST, "Invalid email address").into_response();
}
};
let new_subscriber = NewSubscriber { email, name };
match insert_subscriber(&pool, &new_subscriber).await {
2024-02-04 13:48:31 +01:00
Ok(_) => {
return (StatusCode::OK,).into_response();
2024-02-04 13:48:31 +01:00
}
Err(_) => {
return (StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong").into_response();
2024-02-04 13:48:31 +01:00
}
}
}
#[tracing::instrument(
name = "Saving new subscriber details in the database",
2024-02-12 10:55:23 +01:00
skip(new_subscriber, pool)
2024-02-04 13:48:31 +01:00
)]
2024-02-12 10:55:23 +01:00
pub async fn insert_subscriber(
pool: &PgPool,
new_subscriber: &NewSubscriber,
) -> Result<(), sqlx::Error> {
let _ = sqlx::query!(
r#"
2024-02-04 13:48:31 +01:00
INSERT INTO subscriptions (id, email, name, subscribed_at)
VALUES ($1, $2, $3, $4)
"#,
Uuid::new_v4(),
2024-02-12 10:55:23 +01:00
new_subscriber.email.as_ref(),
new_subscriber.name.as_ref(),
Utc::now()
)
// We use `get_ref` to get an immutable reference to the `PgConnection`
// wrapped by `web::Data`.
2024-02-04 13:48:31 +01:00
.execute(pool)
2024-01-30 21:43:32 +01:00
.await
2024-02-04 13:48:31 +01:00
.map_err(|e| {
tracing::error!("Failed to execute query: {:?}", e);
e
});
2024-02-04 13:48:31 +01:00
Ok(())
}
2023-12-30 22:21:57 +01:00
pub fn routes_subscriptions(pool: PgPool) -> Router {
Router::new()
.route("/subscriptions", post(subscribe))
.with_state(pool)
2023-12-30 22:21:57 +01:00
}