armature_lambda/
response.rs

1//! Lambda response conversion.
2
3use bytes::Bytes;
4use lambda_http::{Body, Response};
5use std::collections::HashMap;
6
7/// Lambda HTTP response.
8pub struct LambdaResponse {
9    /// Status code.
10    pub status: u16,
11    /// Response headers.
12    pub headers: HashMap<String, String>,
13    /// Response body.
14    pub body: Bytes,
15    /// Whether body is base64 encoded.
16    pub is_base64: bool,
17}
18
19impl LambdaResponse {
20    /// Create a new response.
21    pub fn new(status: u16, body: impl Into<Bytes>) -> Self {
22        Self {
23            status,
24            headers: HashMap::new(),
25            body: body.into(),
26            is_base64: false,
27        }
28    }
29
30    /// Create an OK response.
31    pub fn ok(body: impl Into<Bytes>) -> Self {
32        Self::new(200, body)
33    }
34
35    /// Create a JSON response.
36    pub fn json<T: serde::Serialize>(data: &T) -> Result<Self, serde_json::Error> {
37        let body = serde_json::to_vec(data)?;
38        Ok(Self::new(200, body).header("content-type", "application/json"))
39    }
40
41    /// Create an error response.
42    pub fn error(status: u16, message: impl Into<String>) -> Self {
43        let body = serde_json::json!({
44            "error": message.into()
45        });
46        Self::new(status, serde_json::to_vec(&body).unwrap_or_default())
47            .header("content-type", "application/json")
48    }
49
50    /// Create a not found response.
51    pub fn not_found() -> Self {
52        Self::error(404, "Not Found")
53    }
54
55    /// Create an internal server error response.
56    pub fn internal_error(message: impl Into<String>) -> Self {
57        Self::error(500, message)
58    }
59
60    /// Add a header.
61    pub fn header(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
62        self.headers.insert(name.into(), value.into());
63        self
64    }
65
66    /// Set content type.
67    pub fn content_type(self, content_type: impl Into<String>) -> Self {
68        self.header("content-type", content_type)
69    }
70
71    /// Mark body as base64 encoded.
72    pub fn base64(mut self) -> Self {
73        self.is_base64 = true;
74        self
75    }
76
77    /// Convert to lambda_http::Response.
78    pub fn into_lambda_response(self) -> Response<Body> {
79        let mut builder = Response::builder().status(self.status);
80
81        for (name, value) in &self.headers {
82            builder = builder.header(name, value);
83        }
84
85        let body = if self.is_base64 {
86            Body::Binary(self.body.to_vec())
87        } else if let Ok(s) = String::from_utf8(self.body.to_vec()) {
88            Body::Text(s)
89        } else {
90            Body::Binary(self.body.to_vec())
91        };
92
93        builder.body(body).unwrap_or_else(|_| {
94            Response::builder()
95                .status(500)
96                .body(Body::Text("Internal Server Error".to_string()))
97                .unwrap()
98        })
99    }
100}
101
102impl Default for LambdaResponse {
103    fn default() -> Self {
104        Self::new(200, Bytes::new())
105    }
106}