Skip to content

Commit 8463eaa

Browse files
committed
Provide context when deserialization fails.
Use serde_path_to_error to provide a little bit more information about the serde failure. Signed-off-by: David Calavera <david.calavera@gmail.com>
1 parent 393d644 commit 8463eaa

File tree

4 files changed

+49
-10
lines changed

4 files changed

+49
-10
lines changed

lambda-runtime/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,4 @@ tracing = { version = "0.1.37", features = ["log"] }
4141
tower = { version = "0.4", features = ["util"] }
4242
tokio-stream = "0.1.2"
4343
lambda_runtime_api_client = { version = "0.8", path = "../lambda-runtime-api-client" }
44+
serde_path_to_error = "0.1.11"

lambda-runtime/src/deserializer.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use std::{error::Error, fmt};
2+
3+
use serde::Deserialize;
4+
5+
use crate::{Context, LambdaEvent};
6+
7+
/// Event payload deserialization error.
8+
/// Returned when the data sent to the function cannot be deserialized
9+
/// into the type that the function receives.
10+
#[derive(Debug)]
11+
pub(crate) struct DeserializeError {
12+
inner: serde_path_to_error::Error<serde_json::Error>,
13+
}
14+
15+
impl fmt::Display for DeserializeError {
16+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17+
writeln!(
18+
f,
19+
"failed to deserialize the incoming data into the function payload's type: {}",
20+
self.inner
21+
)
22+
}
23+
}
24+
25+
impl Error for DeserializeError {
26+
fn source(&self) -> Option<&(dyn Error + 'static)> {
27+
Some(&self.inner)
28+
}
29+
}
30+
31+
/// Deserialize the data sent to the function into the type that the function receives.
32+
pub(crate) fn deserialize<T>(body: &[u8], context: Context) -> Result<LambdaEvent<T>, DeserializeError>
33+
where
34+
T: for<'de> Deserialize<'de>,
35+
{
36+
let jd = &mut serde_json::Deserializer::from_slice(body);
37+
let payload = serde_path_to_error::deserialize(jd).map_err(|inner| DeserializeError { inner })?;
38+
Ok(LambdaEvent::new(payload, context))
39+
}

lambda-runtime/src/lib.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub use tower::{self, service_fn, Service};
2828
use tower::{util::ServiceFn, ServiceExt};
2929
use tracing::{error, trace, Instrument};
3030

31+
mod deserializer;
3132
mod requests;
3233
#[cfg(test)]
3334
mod simulated;
@@ -149,8 +150,8 @@ where
149150
return Err(parts.status.to_string().into());
150151
}
151152

152-
let body = match serde_json::from_slice(&body) {
153-
Ok(body) => body,
153+
let lambda_event = match deserializer::deserialize(&body, ctx) {
154+
Ok(lambda_event) => lambda_event,
154155
Err(err) => {
155156
let req = build_event_error_request(request_id, err)?;
156157
client.call(req).await.expect("Unable to send response to Runtime APIs");
@@ -161,8 +162,7 @@ where
161162
let req = match handler.ready().await {
162163
Ok(handler) => {
163164
// Catches panics outside of a `Future`
164-
let task =
165-
panic::catch_unwind(panic::AssertUnwindSafe(|| handler.call(LambdaEvent::new(body, ctx))));
165+
let task = panic::catch_unwind(panic::AssertUnwindSafe(|| handler.call(lambda_event)));
166166

167167
let task = match task {
168168
// Catches panics inside of the `Future`

lambda-runtime/src/streaming.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
2-
build_event_error_request, incoming, type_name_of_val, Config, Context, Error, EventErrorRequest, IntoRequest,
3-
LambdaEvent, Runtime,
2+
build_event_error_request, deserializer, incoming, type_name_of_val, Config, Context, Error, EventErrorRequest,
3+
IntoRequest, LambdaEvent, Runtime,
44
};
55
use bytes::Bytes;
66
use futures::FutureExt;
@@ -142,8 +142,8 @@ where
142142
return Err(parts.status.to_string().into());
143143
}
144144

145-
let body = match serde_json::from_slice(&body) {
146-
Ok(body) => body,
145+
let lambda_event = match deserializer::deserialize(&body, ctx) {
146+
Ok(lambda_event) => lambda_event,
147147
Err(err) => {
148148
let req = build_event_error_request(request_id, err)?;
149149
client.call(req).await.expect("Unable to send response to Runtime APIs");
@@ -154,8 +154,7 @@ where
154154
let req = match handler.ready().await {
155155
Ok(handler) => {
156156
// Catches panics outside of a `Future`
157-
let task =
158-
panic::catch_unwind(panic::AssertUnwindSafe(|| handler.call(LambdaEvent::new(body, ctx))));
157+
let task = panic::catch_unwind(panic::AssertUnwindSafe(|| handler.call(lambda_event)));
159158

160159
let task = match task {
161160
// Catches panics inside of the `Future`

0 commit comments

Comments
 (0)