graphql_starter/
request_id.rs

1//! Based on https://github.com/imbolc/tower-request-id, but allowing to generate an [Uuid] from te [RequestId]
2
3use std::{
4    fmt,
5    task::{Context, Poll},
6};
7
8use http::Request;
9use tower::{Layer, Service};
10use ulid::Ulid;
11use uuid::Uuid;
12
13/// A new type around [`ulid::Ulid`]
14#[derive(Clone, Copy, Debug)]
15pub struct RequestId(Ulid);
16
17impl RequestId {
18    fn new() -> Self {
19        Self(Ulid::new())
20    }
21}
22
23impl From<RequestId> for Ulid {
24    fn from(value: RequestId) -> Self {
25        value.0
26    }
27}
28
29impl From<RequestId> for Uuid {
30    fn from(value: RequestId) -> Self {
31        Uuid::from_u128(value.0 .0)
32    }
33}
34
35impl AsRef<Ulid> for &RequestId {
36    fn as_ref(&self) -> &Ulid {
37        &self.0
38    }
39}
40
41impl fmt::Display for RequestId {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
43        let mut buffer = [0; ulid::ULID_LEN];
44        write!(f, "{}", self.0.array_to_str(&mut buffer))
45    }
46}
47
48/// Middleware to use [`RequestId`]
49#[derive(Clone, Debug)]
50pub struct RequestIdService<S> {
51    inner: S,
52}
53
54impl<S> RequestIdService<S> {
55    fn new(inner: S) -> Self {
56        Self { inner }
57    }
58}
59
60impl<B, S> Service<Request<B>> for RequestIdService<S>
61where
62    S: Service<Request<B>>,
63{
64    type Error = S::Error;
65    type Future = S::Future;
66    type Response = S::Response;
67
68    #[inline]
69    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
70        self.inner.poll_ready(cx)
71    }
72
73    fn call(&mut self, mut req: Request<B>) -> Self::Future {
74        let id = RequestId::new();
75        req.extensions_mut().insert(id);
76        self.inner.call(req)
77    }
78}
79
80/// Layer to apply [`RequestIdService`] middleware.
81#[derive(Clone, Debug)]
82pub struct RequestIdLayer;
83
84impl<S> Layer<S> for RequestIdLayer {
85    type Service = RequestIdService<S>;
86
87    fn layer(&self, inner: S) -> Self::Service {
88        RequestIdService::new(inner)
89    }
90}