From db6a62ff2883a05d396de9c6d9f43f7ca046105a Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Mon, 12 Feb 2024 17:04:11 +0000 Subject: [PATCH] chore: [#468] set and propagate request ID It propagates the request ID to the response. If the request does not have an ID it sets a newly generated UUID. Without providing ID: ``` $ curl -i localhost:3001/v1/about/license HTTP/1.1 200 OK content-type: text/html; charset=utf-8 content-length: 1262 x-request-id: cea0efcd-84e0-4f59-96b3-625ca4154396 date: Mon, 12 Feb 2024 16:58:05 GMT ``` Providing ID: ``` $ curl -i -H "x-request-id: a5030c7a-5302-49d4-8e66-f0f0ab0e3ce3" localhost:3001/v1/about/license HTTP/1.1 200 OK content-type: text/html; charset=utf-8 content-length: 1262 x-request-id: a5030c7a-5302-49d4-8e66-f0f0ab0e3ce3 date: Mon, 12 Feb 2024 16:59:31 GMT ``` The response contains the provided ID in the request. --- src/web/api/server/v1/routes.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/web/api/server/v1/routes.rs b/src/web/api/server/v1/routes.rs index 76be1b14..b9150870 100644 --- a/src/web/api/server/v1/routes.rs +++ b/src/web/api/server/v1/routes.rs @@ -3,14 +3,19 @@ use std::env; use std::sync::Arc; use axum::extract::DefaultBodyLimit; +use axum::http::{HeaderName, HeaderValue}; use axum::response::Redirect; use axum::routing::get; use axum::{Json, Router}; +use hyper::Request; use serde_json::{json, Value}; use tower_http::compression::CompressionLayer; use tower_http::cors::CorsLayer; +use tower_http::propagate_header::PropagateHeaderLayer; +use tower_http::request_id::{MakeRequestId, RequestId, SetRequestIdLayer}; use tower_http::trace::{DefaultMakeSpan, DefaultOnRequest, DefaultOnResponse, TraceLayer}; use tracing::Level; +use uuid::Uuid; use super::contexts::{about, category, proxy, settings, tag, torrent, user}; use crate::bootstrap::config::ENV_VAR_CORS_PERMISSIVE; @@ -57,6 +62,8 @@ pub fn router(app_data: Arc) -> Router { .on_request(DefaultOnRequest::new().level(Level::INFO)) .on_response(DefaultOnResponse::new().level(Level::INFO)), ) + .layer(PropagateHeaderLayer::new(HeaderName::from_static("x-request-id"))) + .layer(SetRequestIdLayer::x_request_id(RequestIdGenerator)) } /// Endpoint for container health check. @@ -67,3 +74,13 @@ async fn health_check_handler() -> Json { async fn redirect_to_about() -> Redirect { Redirect::permanent(&format!("/{API_VERSION_URL_PREFIX}/about")) } + +#[derive(Clone, Default)] +struct RequestIdGenerator; + +impl MakeRequestId for RequestIdGenerator { + fn make_request_id(&mut self, _request: &Request) -> Option { + let id = HeaderValue::from_str(&Uuid::new_v4().to_string()).expect("UUID is a valid HTTP header value"); + Some(RequestId::new(id)) + } +}