aws_smithy_http_server/schema/protocol/
rest_json_1.rs1use aws_smithy_runtime_api::http::Headers;
7use aws_smithy_schema::serde::{SerdeError, SerializableStruct, ShapeDeserializer};
8use aws_smithy_schema::{shape_id, Schema, ShapeId};
9
10use crate::body::BoxBody;
11use crate::protocol::rest_json_1::rejection::RequestRejection;
12use crate::protocol::rest_json_1::runtime_error::RuntimeError;
13use crate::response::{IntoResponse, Response};
14use crate::schema::{DeserializeError, HttpModeledError};
15
16use super::response::{log_serialize_failure, stamp_error_extension, stamp_validation_extension};
17use super::rest::RestPolicy;
18use super::{BodyDirective, EventStreamFraming, MetadataRoutedProtocol, ServerProtocol};
19
20#[derive(Debug)]
22pub struct RestJson1 {
27 pub(crate) inner: crate::schema::protocol::rest::RestProtocol<aws_smithy_json::codec::JsonCodec>,
28}
29
30impl Default for RestJson1 {
31 fn default() -> Self {
32 Self::new(false)
33 }
34}
35
36impl RestJson1 {
37 fn new(validate_skipped_values: bool) -> Self {
38 Self {
39 inner: crate::schema::protocol::rest::RestProtocol::new(
40 aws_smithy_json::codec::JsonCodec::new(
41 aws_smithy_json::codec::JsonCodecSettings::builder()
42 .use_json_name(true)
43 .default_timestamp_format(aws_smithy_types::date_time::Format::EpochSeconds)
44 .enforce_strictness(true)
45 .allow_leading_zeros(true)
46 .allow_trailing_decimal_point(true)
47 .allow_empty_integer_part(true)
48 .normalize_arbitrary_precision(true)
49 .validate_skipped_values(validate_skipped_values)
50 .validate_skipped_string_encoding(true)
51 .allow_integral_float_numbers(true)
52 .strict_timestamp_formats(true)
53 .dispatch_null_members(true)
54 .build(),
55 ),
56 crate::schema::protocol::rest_json_1::POLICY,
57 ),
58 }
59 }
60}
61
62static PROTOCOL_ID: ShapeId<'static> = shape_id!("aws.protocols", "restJson1");
63const CONTENT_TYPE: &str = "application/json";
64const ERROR_TYPE_HEADER: http::HeaderName = http::HeaderName::from_static("x-amzn-errortype");
65
66pub(crate) const POLICY: RestPolicy = RestPolicy {
69 payload_deserializer: None,
70 codec_content_type: CONTENT_TYPE,
71 request_content_type_aliases: &[],
72 default_response_content_type: Some(CONTENT_TYPE),
73 untyped_blob_payload_content_type: None,
74 empty_document: true,
75};
76
77impl MetadataRoutedProtocol for RestJson1 {
78 fn from_build_context(
79 ctx: &crate::schema::ProtocolBuildContext<'_>,
80 ) -> Result<Self, crate::schema::routing::RouterBuildError> {
81 let mut protocol =
82 Self::new(crate::schema::settings::get::<bool>(ctx.settings, "validateSkippedValues")?.unwrap_or(false));
83 protocol
84 .inner
85 .prepare_response_plans(ctx.service)
86 .map_err(|err| crate::schema::routing::RouterBuildError::Configuration(err.to_string()))?;
87 Ok(protocol)
88 }
89
90 fn build_router(
91 &self,
92 ctx: crate::schema::routing::RouterBuildContext<'_>,
93 ) -> Result<
94 impl crate::schema::routing::MetadataProtocolRouter + 'static + use<>,
95 crate::schema::routing::RouterBuildError,
96 > {
97 crate::schema::routing::rest_router(&ctx, CONTENT_TYPE, &[])
98 }
99
100 fn event_stream_framing(&self) -> Option<EventStreamFraming<'_>> {
101 Some(
102 EventStreamFraming::new(self.inner.codec(), CONTENT_TYPE)
103 .unset_initial_response_payload(b"{}")
104 .exception_http_bindings(true),
105 )
106 }
107}
108
109impl ServerProtocol for RestJson1 {
110 fn protocol_id(&self) -> &'static ShapeId<'static> {
111 &PROTOCOL_ID
112 }
113
114 fn validate_request_headers(
115 &self,
116 operation: &crate::schema::OperationSchema<'_>,
117 headers: &Headers,
118 ) -> Result<(), DeserializeError> {
119 self.inner.check_accept(operation.output(), headers)
120 }
121
122 fn request_body_requirement(&self, operation: &crate::schema::OperationSchema<'_>) -> BodyDirective {
123 if self.inner.reads_request_body(operation.input()) {
124 BodyDirective::Collect
125 } else {
126 BodyDirective::Skip
127 }
128 }
129
130 fn deserialize_request<'a>(
131 &'a self,
132 input: &Schema<'_>,
133 request: &'a aws_smithy_runtime_api::http::Request<bytes::Bytes>,
134 ) -> Result<Box<dyn ShapeDeserializer + 'a>, DeserializeError> {
135 self.inner.deserialize_request(input, request)
136 }
137
138 fn serialize_response(&self, output: &Schema<'_>, value: &dyn SerializableStruct) -> Response {
139 self.inner
140 .serialize_response(output, value)
141 .unwrap_or_else(serialization_failure)
142 }
143
144 fn serialize_streaming_response(
145 &self,
146 output: &Schema<'_>,
147 value: &dyn SerializableStruct,
148 _streaming_member: &Schema<'_>,
149 body: Option<BoxBody>,
150 ) -> Response {
151 self.inner
152 .serialize_streaming_response(output, value, body.unwrap_or_else(crate::body::empty))
153 .unwrap_or_else(serialization_failure)
154 }
155
156 fn serialize_error(&self, error: &dyn HttpModeledError) -> Response {
157 let schema = error.schema();
158 let name = schema.shape_id().shape_name();
159 let content_type = match error.operation_schema() {
161 Some(operation) => self.inner.response_content_type(operation.output()),
162 None => Some(CONTENT_TYPE),
163 };
164 let result =
165 self.inner
166 .serialize_modeled_error(self.inner.codec(), schema, error, error.status_code(), content_type);
167 match result {
168 Ok(mut response) => {
169 if !response.headers().contains_key(&ERROR_TYPE_HEADER) {
171 if let Ok(value) = http::HeaderValue::try_from(name) {
172 response.headers_mut().insert(ERROR_TYPE_HEADER, value);
173 }
174 }
175 stamp_error_extension(response, name)
176 }
177 Err(err) => serialization_failure(err),
178 }
179 }
180
181 fn serialize_routing_error(&self, err: &crate::schema::routing::RoutingError) -> Response {
182 use crate::protocol::rest::router::Error;
183 use crate::schema::routing::RoutingErrorKind;
184 if err.kind() == RoutingErrorKind::MissingContentType {
185 return self.serialize_rejection(
186 crate::rejection::MissingContentTypeReason::UnexpectedMimeType {
187 expected_mime: err.expected_content_type().and_then(|expected| expected.parse().ok()),
188 found_mime: None,
189 }
190 .into(),
191 );
192 }
193 let error = match err.kind() {
194 RoutingErrorKind::MethodNotAllowed => Error::MethodNotAllowed,
195 _ => Error::NotFound,
196 };
197 IntoResponse::<RestJson1>::into_response(error)
198 }
199
200 fn serialize_runtime_error(&self, error: crate::runtime_error::RuntimeError) -> Response {
201 IntoResponse::<RestJson1>::into_response(RuntimeError::from(error))
202 }
203
204 fn serialize_rejection(&self, err: DeserializeError) -> Response {
208 match err {
209 DeserializeError::InitialRequestFrame(reason) => {
210 IntoResponse::<RestJson1>::into_response(RuntimeError::Validation(reason))
211 }
212 DeserializeError::Serde(err) => {
213 IntoResponse::<RestJson1>::into_response(RuntimeError::Serialization(crate::Error::new(err)))
214 }
215 DeserializeError::BodyCollection(err) => {
216 IntoResponse::<RestJson1>::into_response(RuntimeError::Serialization(crate::Error::new(err)))
217 }
218 DeserializeError::UnsupportedMediaType(reason) => IntoResponse::<RestJson1>::into_response(
219 RuntimeError::from(RequestRejection::MissingContentType(*reason)),
220 ),
221 DeserializeError::NotAcceptable => {
222 IntoResponse::<RestJson1>::into_response(RuntimeError::from(RequestRejection::NotAcceptable))
223 }
224 DeserializeError::ConstraintViolation(err) => stamp_validation_extension(self.serialize_error(&*err)),
225 DeserializeError::InternalFailure(err) => {
226 IntoResponse::<RestJson1>::into_response(RuntimeError::InternalFailure(err))
227 }
228 }
229 }
230}
231
232fn serialization_failure(err: SerdeError) -> Response {
233 log_serialize_failure(&err);
234 IntoResponse::<RestJson1>::into_response(RuntimeError::Serialization(crate::Error::new(err)))
235}