actix_web_middleware_requestid/
lib.rs1use std::task::{Context, Poll};
34
35use actix_service::{Service, Transform};
36use actix_web::error::ErrorBadRequest;
37use actix_web::http::header::{HeaderName, HeaderValue};
38use actix_web::Result;
39use actix_web::{dev, Error, FromRequest, HttpMessage, HttpRequest};
40use actix_web::{dev::ServiceRequest, dev::ServiceResponse};
41use futures::future::{err, ok, Ready};
42
43pub const REQUEST_ID_HEADER: &str = "x-request-id";
45
46pub struct RequestIDWrapper;
48
49impl<S, B> Transform<S> for RequestIDWrapper
50where
51 S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
52 S::Future: 'static,
53 B: 'static,
54{
55 type Request = ServiceRequest;
56 type Response = ServiceResponse<B>;
57 type Error = Error;
58 type InitError = ();
59 type Transform = RequestIDMiddleware<S>;
60 type Future = Ready<Result<Self::Transform, Self::InitError>>;
61
62 fn new_transform(&self, service: S) -> Self::Future {
63 ok(RequestIDMiddleware { service })
64 }
65}
66
67pub struct RequestIDMiddleware<S> {
69 service: S,
70}
71
72impl<S, B> Service for RequestIDMiddleware<S>
73where
74 S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
75 S::Future: 'static,
76 B: 'static,
77{
78 type Request = ServiceRequest;
79 type Response = ServiceResponse<B>;
80 type Error = Error;
81 type Future = S::Future;
82
83 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
84 self.service.poll_ready(cx)
85 }
86
87 fn call(&mut self, req: ServiceRequest) -> Self::Future {
88 use rand::{distributions::Alphanumeric, thread_rng, Rng};
89
90 let request_id: String = thread_rng().sample_iter(&Alphanumeric).take(10).collect();
92
93 let mut req = req;
95
96 req.headers_mut().append(
98 HeaderName::from_static(REQUEST_ID_HEADER),
99 HeaderValue::from_str(&request_id).unwrap(),
100 );
101
102 req.extensions_mut().insert(RequestID(request_id));
104
105 self.service.call(req)
107 }
108}
109
110pub struct RequestID(pub String);
112
113impl FromRequest for RequestID {
114 type Error = Error;
115 type Future = Ready<Result<Self, Self::Error>>;
116 type Config = ();
117
118 fn from_request(req: &HttpRequest, _payload: &mut dev::Payload) -> Self::Future {
119 if let Some(RequestID(req_id)) = req.extensions().get::<RequestID>() {
120 ok(RequestID(req_id.clone()))
121 } else {
122 err(ErrorBadRequest("request id is missing"))
123 }
124 }
125}