aws_types/
request_id.rs
1use aws_smithy_runtime_api::client::result::SdkError;
9use aws_smithy_runtime_api::http::Headers;
10use aws_smithy_runtime_api::http::Response;
11use aws_smithy_types::error::metadata::{Builder as ErrorMetadataBuilder, ErrorMetadata};
12
13const AWS_REQUEST_ID: &str = "aws_request_id";
15
16pub trait RequestId {
18 fn request_id(&self) -> Option<&str>;
20}
21
22impl<E> RequestId for SdkError<E, Response> {
23 fn request_id(&self) -> Option<&str> {
24 match self {
25 Self::ResponseError(err) => err.raw().headers().request_id(),
26 Self::ServiceError(err) => err.raw().headers().request_id(),
27 _ => None,
28 }
29 }
30}
31
32impl RequestId for ErrorMetadata {
33 fn request_id(&self) -> Option<&str> {
34 self.extra(AWS_REQUEST_ID)
35 }
36}
37
38impl<B> RequestId for Response<B> {
39 fn request_id(&self) -> Option<&str> {
40 self.headers().request_id()
41 }
42}
43
44impl RequestId for Headers {
45 fn request_id(&self) -> Option<&str> {
46 self.get("x-amzn-requestid")
47 .or(self.get("x-amz-request-id"))
48 }
49}
50
51impl<O, E> RequestId for Result<O, E>
52where
53 O: RequestId,
54 E: RequestId,
55{
56 fn request_id(&self) -> Option<&str> {
57 match self {
58 Ok(ok) => ok.request_id(),
59 Err(err) => err.request_id(),
60 }
61 }
62}
63
64pub fn apply_request_id(builder: ErrorMetadataBuilder, headers: &Headers) -> ErrorMetadataBuilder {
66 if let Some(request_id) = headers.request_id() {
67 builder.custom(AWS_REQUEST_ID, request_id)
68 } else {
69 builder
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use crate::request_id::{apply_request_id, RequestId, AWS_REQUEST_ID};
76 use aws_smithy_runtime_api::client::orchestrator::HttpResponse;
77 use aws_smithy_runtime_api::client::result::SdkError;
78 use aws_smithy_runtime_api::http::Headers;
79 use aws_smithy_types::body::SdkBody;
80 use aws_smithy_types::error::ErrorMetadata;
81 use http::{HeaderValue, Response};
82
83 #[test]
84 fn test_request_id_sdk_error() {
85 let without_request_id =
86 || HttpResponse::try_from(Response::builder().body(SdkBody::empty()).unwrap()).unwrap();
87 let with_request_id = || {
88 HttpResponse::try_from(
89 Response::builder()
90 .header(
91 "x-amzn-requestid",
92 HeaderValue::from_static("some-request-id"),
93 )
94 .body(SdkBody::empty())
95 .unwrap(),
96 )
97 .unwrap()
98 };
99 assert_eq!(
100 None,
101 SdkError::<(), _>::response_error("test", without_request_id()).request_id()
102 );
103 assert_eq!(
104 Some("some-request-id"),
105 SdkError::<(), _>::response_error("test", with_request_id()).request_id()
106 );
107 assert_eq!(
108 None,
109 SdkError::service_error((), without_request_id()).request_id()
110 );
111 assert_eq!(
112 Some("some-request-id"),
113 SdkError::service_error((), with_request_id()).request_id()
114 );
115 }
116
117 #[test]
118 fn test_extract_request_id() {
119 let mut headers = Headers::new();
120 assert_eq!(None, headers.request_id());
121
122 headers.append(
123 "x-amzn-requestid",
124 HeaderValue::from_static("some-request-id"),
125 );
126 assert_eq!(Some("some-request-id"), headers.request_id());
127
128 headers.append(
129 "x-amz-request-id",
130 HeaderValue::from_static("other-request-id"),
131 );
132 assert_eq!(Some("some-request-id"), headers.request_id());
133
134 headers.remove("x-amzn-requestid");
135 assert_eq!(Some("other-request-id"), headers.request_id());
136 }
137
138 #[test]
139 fn test_apply_request_id() {
140 let mut headers = Headers::new();
141 assert_eq!(
142 ErrorMetadata::builder().build(),
143 apply_request_id(ErrorMetadata::builder(), &headers).build(),
144 );
145
146 headers.append(
147 "x-amzn-requestid",
148 HeaderValue::from_static("some-request-id"),
149 );
150 assert_eq!(
151 ErrorMetadata::builder()
152 .custom(AWS_REQUEST_ID, "some-request-id")
153 .build(),
154 apply_request_id(ErrorMetadata::builder(), &headers).build(),
155 );
156 }
157
158 #[test]
159 fn test_error_metadata_request_id_impl() {
160 let err = ErrorMetadata::builder()
161 .custom(AWS_REQUEST_ID, "some-request-id")
162 .build();
163 assert_eq!(Some("some-request-id"), err.request_id());
164 }
165}