Skip to main content

wadm/server/
parser.rs

1use async_nats::HeaderMap;
2
3use wadm_types::Manifest;
4
5/// The name of the header in the NATS request to use for content type inference. The header value
6/// should be a valid MIME type
7pub const CONTENT_TYPE_HEADER: &str = "Content-Type";
8
9// NOTE(thomastaylor312): If we do _anything_ else with mime types in the server, we should just
10// pull in the `mime` crate instead
11const YAML_MIME: &str = "application/yaml";
12const JSON_MIME: &str = "application/json";
13
14/// Parse the incoming bytes to a manifest
15///
16/// This function takes the optional headers from a NATS request to use them as a type hint for
17/// parsing
18pub fn parse_manifest(data: Vec<u8>, headers: Option<&HeaderMap>) -> anyhow::Result<Manifest> {
19    // There is far too much cloning here, but there is no way to just return a reference to a &str
20    let content_type = headers
21        .and_then(|map| map.get(CONTENT_TYPE_HEADER).cloned())
22        .map(|value| value.as_str().to_owned());
23    if let Some(content_type) = content_type {
24        match content_type.as_str() {
25            JSON_MIME => serde_json::from_slice(&data).map_err(anyhow::Error::from),
26            YAML_MIME => serde_yaml::from_slice(&data).map_err(anyhow::Error::from),
27            _ => {
28                // If the user passed a non-supported mime type, we should let them know rather than
29                // just falling back
30                Err(anyhow::anyhow!(
31                    "Unsupported content type {content_type} given. Wadm supports YAML and JSON"
32                ))
33            }
34        }
35    } else {
36        parse_yaml_or_json(data)
37    }
38}
39
40/// Parse the bytes as yaml or json (in that order)
41fn parse_yaml_or_json(data: Vec<u8>) -> anyhow::Result<Manifest> {
42    serde_yaml::from_slice(&data).or_else(|e| {
43        serde_json::from_slice(&data).map_err(|err| {
44            // Combine both errors in case one was a legit parsing failure due to invalid data
45            anyhow::anyhow!("JSON parsing failed: {err:?}")
46                .context(format!("YAML parsing failed: {e:?}"))
47        })
48    })
49}