Skip to content

Commit

Permalink
refactor: remove opionated middleware and tracing, cleanup unused imp…
Browse files Browse the repository at this point in the history
…orts, add proper creation of tests db
  • Loading branch information
koskeller committed Feb 17, 2024
1 parent 768b6d4 commit 94dd634
Show file tree
Hide file tree
Showing 9 changed files with 24 additions and 89 deletions.
2 changes: 2 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ PORT=8080

DATABASE_URL="postgres://postgres:[email protected]:5432/example"
DATABASE_POOL_MAX_SIZE=50
# Used in tests to remove the database prefix from DATABASE_URL and replace it with a random database name.
DATABASE_NAME="example"

# Configures which modules `tracing_subscriber` should emit logs for.
#
Expand Down
7 changes: 2 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ name = "server"

[dependencies]
tokio = { version = "1.35.0", features = ["full"] }

axum = "0.7.3"
hyper = "1.1.0"
tower = { version = "0.4.13", features = []}
tower-http = { version = "0.5.0", features = ["trace", "timeout", "sensitive-headers", "request-id", "cors"] }
tower-http = { version = "0.5.0", features = ["timeout", "request-id", "cors"] }

sqlx = { version = "0.7.3", features = ["postgres", "runtime-tokio-rustls", "macros", "migrate", "chrono", "json", "uuid"] }

Expand All @@ -30,5 +29,4 @@ serde_json = "1.0.102"
uuid = { version = "1.4.0", features = ["v4", "serde"] }

dotenv = "0.15.0"
thiserror = "1.0.43"
anyhow = "1.0.71"
23 changes: 5 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ use axum::Router;
use std::sync::Arc;

mod cfg;
pub use cfg::*;
mod telemetry;
pub use telemetry::*;
mod middleware;
pub use middleware::*;
mod db;
pub mod middleware;
pub mod routes;
pub mod telemetry;

pub use cfg::*;
pub use db::*;
mod routes;

#[derive(Clone)]
pub struct AppState {
Expand All @@ -20,15 +19,6 @@ pub struct AppState {
pub fn router(cfg: Config, db: Db) -> Router {
let app_state = AppState { db, cfg };

// Middleware that adds high level tracing to a Service.
// Trace comes with good defaults but also supports customizing many aspects of the output:
// https://docs.rs/tower-http/latest/tower_http/trace/index.html
let trace_layer = telemetry::trace_layer();

// Hiding sensitive headers is a good security practice as it prevents sensitive information
// such as authorization tokens and cookies from being leaked to unauthorized parties.
let (req_headers_layer, resp_headers_layer) = telemetry::sensitive_headers_layers();

// Sets 'x-request-id' header with randomly generated uuid v4.
let request_id_layer = middleware::request_id_layer();

Expand All @@ -46,10 +36,7 @@ pub fn router(cfg: Config, db: Db) -> Router {
.merge(routes::router())
.layer(cors_layer)
.layer(timeout_layer)
.layer(resp_headers_layer)
.layer(propagate_request_id_layer)
.layer(trace_layer)
.layer(req_headers_layer)
.layer(request_id_layer)
.with_state(app_state)
}
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use server::{setup_tracing, Configuration, Db};
use server::{telemetry, Configuration, Db};
use tokio::net::TcpListener;

#[tokio::main]
Expand All @@ -8,7 +8,7 @@ async fn main() {
dotenv::dotenv().ok();

// Tries to load tracing config from environment (RUST_LOG) or uses "debug".
setup_tracing();
telemetry::setup_tracing();

// Parse configuration from the environment.
// This will exit with a help message if something is wrong.
Expand Down
2 changes: 1 addition & 1 deletion src/routes/health_check.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use axum::Json;
use serde_json::{json, Value};

pub async fn health_check_handler() -> Json<Value> {
pub async fn health_check() -> Json<Value> {
Json(json!({ "status": "ok" }))
}
5 changes: 2 additions & 3 deletions src/routes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use axum::{routing::get, Router};

mod health_check;
pub(crate) use health_check::health_check_handler;
pub mod health_check;

use crate::AppState;

pub fn router() -> Router<AppState> {
Router::new().route("/health_check", get(health_check_handler))
Router::new().route("/health_check", get(health_check::health_check))
}
42 changes: 0 additions & 42 deletions src/telemetry.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
use hyper::header;
use std::sync::Arc;
use tower_http::{
classify::{ServerErrorsAsFailures, SharedClassifier},
sensitive_headers::{SetSensitiveRequestHeadersLayer, SetSensitiveResponseHeadersLayer},
trace::{DefaultMakeSpan, DefaultOnResponse, TraceLayer},
};
use tracing::Level;
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};

// The `EnvFilter` type is used to filter log events based on the value of an environment variable.
Expand All @@ -20,37 +12,3 @@ pub fn setup_tracing() {
.with(formatting_layer)
.init()
}

/// Returns a `TraceLayer` for HTTP requests and responses.
/// The `TraceLayer` is used to trace requests and responses in the application.
/// It includes headers and sets the log level to `INFO`.
pub fn trace_layer() -> TraceLayer<SharedClassifier<ServerErrorsAsFailures>> {
TraceLayer::new_for_http()
.make_span_with(
DefaultMakeSpan::new()
.include_headers(true)
.level(Level::INFO),
)
.on_response(
DefaultOnResponse::new()
.include_headers(true)
.level(Level::INFO),
)
}

/// Middleware that marks headers as sensitive.
pub fn sensitive_headers_layers() -> (
SetSensitiveRequestHeadersLayer,
SetSensitiveResponseHeadersLayer,
) {
let headers: Arc<[_]> = Arc::new([
header::AUTHORIZATION,
header::PROXY_AUTHORIZATION,
header::COOKIE,
header::SET_COOKIE,
]);

let req = SetSensitiveRequestHeadersLayer::from_shared(Arc::clone(&headers));
let resp = SetSensitiveResponseHeadersLayer::from_shared(headers);
(req, resp)
}
24 changes: 9 additions & 15 deletions tests/api/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ use std::sync::Once;
use tower::ServiceExt;
use uuid::Uuid;

use server::{router, setup_tracing, Configuration, Db};
use server::{router, telemetry, Configuration, Db};

static TRACING: Once = Once::new();

pub struct TestApp {
pub router: Router,
pub db: Db,
pub reqwest: reqwest::Client,
}

impl TestApp {
Expand All @@ -24,7 +23,7 @@ impl TestApp {
std::env::set_var("PORT", "0");

// Setup tracing. Once.
TRACING.call_once(setup_tracing);
TRACING.call_once(telemetry::setup_tracing);

// Parse configuration from the environment.
// This will exit with a help message if something is wrong.
Expand All @@ -40,15 +39,8 @@ impl TestApp {
tracing::debug!("Running migrations");
db.migrate().await.expect("Failed to run migrations");

// Reqwest client for integration tests.
let reqwest = reqwest::Client::new();

let app = router(cfg, db.clone());
Self {
db,
router: app,
reqwest,
}
let router = router(cfg, db.clone());
Self { db, router }
}

pub async fn request(&self, req: Request<Body>) -> Response<Body> {
Expand All @@ -58,16 +50,18 @@ impl TestApp {

/// Creates db with a random name for tests.
pub async fn create_test_db(db_dsn: &str) -> String {
let db_name =
std::env::var("DATABASE_NAME").expect("Missing DATABASE_NAME environment variable");
let db_dsn = db_dsn
.strip_suffix("example")
.expect("Failed to remove db name from dsn_url, should be 'example'");
.strip_suffix(&db_name)
.expect("Failed to remove db name from dsn_url");
let randon_db_name = Uuid::new_v4().to_string();
let db_url = format!("{}{}", &db_dsn, randon_db_name);
let mut conn = PgConnection::connect(db_dsn)
.await
.expect("Failed to connect to Postgres");
conn.execute(format!(r#"CREATE DATABASE "{}";"#, randon_db_name).as_str())
.await
.expect("Failed to create database");
.expect("Failed to create test database");
db_url
}

0 comments on commit 94dd634

Please sign in to comment.