feat(log): rudimentary logging

- Changed route `subscribe` into `subscriptions`
This commit is contained in:
minhtrannhat 2024-05-06 00:49:17 -04:00
parent 2c9dab01bb
commit ccf49ee214
Signed by: minhtrannhat
GPG Key ID: E13CFA85C53F8062
7 changed files with 116 additions and 9 deletions

83
Cargo.lock generated
View File

@ -285,6 +285,17 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -613,6 +624,8 @@ dependencies = [
"actix-web", "actix-web",
"chrono", "chrono",
"config", "config",
"env_logger",
"log",
"reqwest", "reqwest",
"serde", "serde",
"sqlx", "sqlx",
@ -629,6 +642,19 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "env_logger"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.1" version = "1.0.1"
@ -899,6 +925,15 @@ dependencies = [
"unicode-segmentation", "unicode-segmentation",
] ]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.9" version = "0.3.9"
@ -995,6 +1030,12 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "1.2.0" version = "1.2.0"
@ -1363,7 +1404,7 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi 0.3.9",
"libc", "libc",
] ]
@ -2332,6 +2373,15 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.59" version = "1.0.59"
@ -2740,6 +2790,37 @@ dependencies = [
"wasite", "wasite",
] ]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "windows-core" name = "windows-core"
version = "0.52.0" version = "0.52.0"

View File

@ -17,6 +17,8 @@ edition = "2021"
[dependencies] [dependencies]
actix-web = "4.5.1" actix-web = "4.5.1"
reqwest = "0.12.2" reqwest = "0.12.2"
env_logger = "0.9"
log = "0.4"
serde = { version = "1.0.197", features = ["derive"] } serde = { version = "1.0.197", features = ["derive"] }
tokio = { version = "1.36.0", features = ["full"] } tokio = { version = "1.36.0", features = ["full"] }
config = "0.13" config = "0.13"

View File

@ -2,8 +2,8 @@
## Routes ## Routes
- `health_check`: returns a HTTP code 200 if the server is up and running. Response body is empty. - `health_check`: GET - returns a HTTP code 200 if the server is up and running. Response body is empty.
- `subscribe` returns a HTTP code 200 if the user successfully subscribed to our email newsletter service. 400 if data is missing or invalid. - `subscriptions` POST - returns a HTTP code 200 if the user successfully subscribed to our email newsletter service. 400 if data is missing or invalid.
## Other topics ## Other topics

View File

@ -1,12 +1,15 @@
use std::net::TcpListener; use std::net::TcpListener;
use email_newsletter_api::{configuration::get_configuration, startup}; use email_newsletter_api::{configuration::get_configuration, startup};
use env_logger::Env;
use sqlx::PgPool; use sqlx::PgPool;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), std::io::Error> { async fn main() -> Result<(), std::io::Error> {
let configuration = get_configuration().expect("Failed to read configuration"); let configuration = get_configuration().expect("Failed to read configuration");
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
let db_conn = PgPool::connect(&configuration.database.connection_string()) let db_conn = PgPool::connect(&configuration.database.connection_string())
.await .await
.expect("Failed to connect to PostgreSQL"); .expect("Failed to connect to PostgreSQL");

View File

@ -13,6 +13,15 @@ pub async fn subscribe_route(
form: web::Form<FormData>, form: web::Form<FormData>,
db_conn_pool: web::Data<PgPool>, db_conn_pool: web::Data<PgPool>,
) -> HttpResponse { ) -> HttpResponse {
let request_id = Uuid::new_v4();
log::info!(
"request_id {} - Saving '{}' '{}' as a new subscriber in PostgreSQL",
request_id,
form.name,
form.email
);
match sqlx::query!( match sqlx::query!(
r#" r#"
INSERT INTO subscriptions (id, email, name, subscribed_at) INSERT INTO subscriptions (id, email, name, subscribed_at)
@ -26,9 +35,19 @@ pub async fn subscribe_route(
.execute(db_conn_pool.get_ref()) .execute(db_conn_pool.get_ref())
.await .await
{ {
Ok(_) => HttpResponse::Ok().finish(), Ok(_) => {
Err(e) => { log::info!(
println!("Failed to execute query: {}", e); "request_id {} - Saved new subscriber details in PostgreSQL",
request_id
);
HttpResponse::Ok().finish()
}
Err(err) => {
log::info!(
"request_id {} - Failed to execute query: {:?}",
request_id,
err
);
HttpResponse::InternalServerError().finish() HttpResponse::InternalServerError().finish()
} }
} }

View File

@ -1,5 +1,6 @@
use crate::routes::{healthcheck_route, subscribe_route}; use crate::routes::{healthcheck_route, subscribe_route};
use actix_web::dev::Server; use actix_web::dev::Server;
use actix_web::middleware::Logger;
use actix_web::{web, App, HttpServer}; use actix_web::{web, App, HttpServer};
use sqlx::PgPool; use sqlx::PgPool;
use std::net::TcpListener; use std::net::TcpListener;
@ -11,8 +12,9 @@ pub fn run(listener: TcpListener, db_conn_pool: PgPool) -> Result<Server, std::i
let server = HttpServer::new(move || { let server = HttpServer::new(move || {
App::new() App::new()
.wrap(Logger::default())
.route("/health_check", web::get().to(healthcheck_route)) .route("/health_check", web::get().to(healthcheck_route))
.route("/subscribe", web::post().to(subscribe_route)) .route("/subscriptions", web::post().to(subscribe_route))
.app_data(db_conn_pool.clone()) .app_data(db_conn_pool.clone())
}) })
.listen(listener)? .listen(listener)?

View File

@ -11,7 +11,7 @@ async fn subscribe_returns_a_200_for_valid_form_data() {
let body = "name=le%20test&email=le_test%40gmail.com"; let body = "name=le%20test&email=le_test%40gmail.com";
let response = client let response = client
.post(&format!("{}/subscribe", &test_app.address)) .post(&format!("{}/subscriptions", &test_app.address))
.header("Content-Type", "application/x-www-form-urlencoded") .header("Content-Type", "application/x-www-form-urlencoded")
.body(body) .body(body)
.send() .send()
@ -44,7 +44,7 @@ async fn subscribe_returns_a_400_when_data_is_missing() {
for (invalid_body, error_message) in test_cases { for (invalid_body, error_message) in test_cases {
let response = client let response = client
.post(&format!("{}/subscribe", &test_app.address)) .post(&format!("{}/subscriptions", &test_app.address))
.header("Content-Type", "application/x-www-form-urlencoded") .header("Content-Type", "application/x-www-form-urlencoded")
.body(invalid_body) .body(invalid_body)
.send() .send()