tower_request_id/
lib.rs

1//! A tiny [tower] ([hyper], [axum], [warp] etc) service to generate a random id for each
2//! incoming request.
3//!
4//! ## Usage
5//!
6//! After adding the [`RequestIdLayer`] into the [axum] middlewares the request id is available in
7//! the [`http::Request::extensions()`]. For the [tracing] integration, please refer to the
8//! [logging example].
9//!
10//! [tower]: https://crates.io/crates/tower
11//! [hyper]: https://crates.io/crates/hyper
12//! [axum]: https://crates.io/crates/axum
13//! [warp]: https://crates.io/crates/warp
14//! [tracing]: https://crates.io/crates/tracing
15//! [`Request.extensions()`]: https://docs.rs/http/0.2.5/http/request/struct.Request.html#method.extensions
16//! [logging example]: https://github.com/imbolc/tower-request-id/blob/main/examples/logging.rs
17
18use http::Request;
19use std::fmt;
20use std::task::{Context, Poll};
21use tower_layer::Layer;
22use tower_service::Service;
23use ulid::Ulid;
24
25/// A newtype around [`ulid::Ulid`]
26#[derive(Debug, Clone)]
27pub struct RequestId(pub Ulid);
28
29impl RequestId {
30    fn new() -> Self {
31        Self(Ulid::new())
32    }
33}
34
35impl fmt::Display for RequestId {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
37        let mut buffer = [0; ulid::ULID_LEN];
38        write!(f, "{}", self.0.to_str(&mut buffer).unwrap_or_default())
39    }
40}
41
42#[derive(Clone, Debug)]
43pub struct RequestIdService<S> {
44    inner: S,
45}
46
47/// Middleware to use [`RequestId`]
48impl<S> RequestIdService<S> {
49    pub fn new(inner: S) -> Self {
50        Self { inner }
51    }
52}
53
54impl<B, S> Service<Request<B>> for RequestIdService<S>
55where
56    S: Service<Request<B>>,
57{
58    type Response = S::Response;
59    type Error = S::Error;
60    type Future = S::Future;
61
62    #[inline]
63    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
64        self.inner.poll_ready(cx)
65    }
66
67    fn call(&mut self, mut req: Request<B>) -> Self::Future {
68        let id = RequestId::new();
69        req.extensions_mut().insert(id);
70        self.inner.call(req)
71    }
72}
73
74/// Layer to apply [`RequestIdService`] middleware.
75#[derive(Clone, Debug)]
76pub struct RequestIdLayer;
77
78impl<S> Layer<S> for RequestIdLayer {
79    type Service = RequestIdService<S>;
80
81    fn layer(&self, inner: S) -> Self::Service {
82        RequestIdService { inner }
83    }
84}