Skip to main content

a3s_boot/http/
request_body.rs

1use super::request::BootRequest;
2use crate::{BootError, Result};
3use serde::de::DeserializeOwned;
4use serde_json::Value;
5
6impl BootRequest {
7    pub fn body_field(&self, name: &str) -> Result<Option<Value>> {
8        let body = self.json::<Value>()?;
9        let Value::Object(fields) = body else {
10            return Err(BootError::BadRequest(
11                "expected JSON object body".to_string(),
12            ));
13        };
14
15        Ok(fields.get(name).filter(|value| !value.is_null()).cloned())
16    }
17
18    pub fn body_field_as<T>(&self, name: &str) -> Result<T>
19    where
20        T: DeserializeOwned,
21    {
22        let Some(value) = self.body_field(name)? else {
23            return Err(BootError::BadRequest(format!("missing body field: {name}")));
24        };
25        deserialize_body_field(name, value)
26    }
27
28    pub fn optional_body_field_as<T>(&self, name: &str) -> Result<Option<T>>
29    where
30        T: DeserializeOwned,
31    {
32        self.body_field(name)?
33            .map(|value| deserialize_body_field(name, value))
34            .transpose()
35    }
36
37    pub fn body_field_string(&self, name: &str) -> Result<String> {
38        let Some(value) = self.body_field(name)? else {
39            return Err(BootError::BadRequest(format!("missing body field: {name}")));
40        };
41        body_field_value_to_string(value)
42    }
43
44    pub fn optional_body_field_string(&self, name: &str) -> Result<Option<String>> {
45        self.body_field(name)?
46            .map(body_field_value_to_string)
47            .transpose()
48    }
49}
50
51fn deserialize_body_field<T>(name: &str, value: Value) -> Result<T>
52where
53    T: DeserializeOwned,
54{
55    serde_json::from_value(value)
56        .map_err(|error| BootError::BadRequest(format!("invalid body field {name}: {error}")))
57}
58
59fn body_field_value_to_string(value: Value) -> Result<String> {
60    match value {
61        Value::String(value) => Ok(value),
62        Value::Bool(value) => Ok(value.to_string()),
63        Value::Number(value) => Ok(value.to_string()),
64        Value::Array(_) | Value::Object(_) => {
65            serde_json::to_string(&value).map_err(|error| BootError::BadRequest(error.to_string()))
66        }
67        Value::Null => Ok("null".to_string()),
68    }
69}