Skip to main content

apigate_core/
parts_ctx.rs

1use axum::extract::FromRequestParts;
2
3use crate::error::ApigateError;
4use http::header::{HeaderName, HeaderValue};
5use http::request::Parts;
6
7pub struct PartsCtx<'a> {
8    service: &'static str,
9    route_path: &'static str,
10    parts: &'a mut Parts,
11}
12
13impl<'a> PartsCtx<'a> {
14    pub fn new(service: &'static str, route_path: &'static str, parts: &'a mut Parts) -> Self {
15        Self {
16            service,
17            route_path,
18            parts,
19        }
20    }
21
22    pub fn service(&self) -> &'static str {
23        self.service
24    }
25
26    pub fn route_path(&self) -> &'static str {
27        self.route_path
28    }
29
30    pub fn method(&self) -> &http::Method {
31        &self.parts.method
32    }
33
34    pub fn uri(&self) -> &http::Uri {
35        &self.parts.uri
36    }
37
38    pub fn uri_mut(&mut self) -> &mut http::Uri {
39        &mut self.parts.uri
40    }
41
42    pub fn headers(&self) -> &http::HeaderMap {
43        &self.parts.headers
44    }
45
46    pub fn headers_mut(&mut self) -> &mut http::HeaderMap {
47        &mut self.parts.headers
48    }
49
50    pub fn header(&self, name: &str) -> Option<&str> {
51        self.parts.headers.get(name).and_then(|v| v.to_str().ok())
52    }
53
54    pub fn set_header(
55        &mut self,
56        name: impl TryInto<HeaderName>,
57        value: impl TryInto<HeaderValue>,
58    ) -> Result<(), ApigateError> {
59        let name = name
60            .try_into()
61            .map_err(|_| ApigateError::bad_request("invalid header name"))?;
62        let value = value
63            .try_into()
64            .map_err(|_| ApigateError::bad_request("invalid header value"))?;
65
66        self.parts.headers.insert(name, value);
67        Ok(())
68    }
69
70    pub fn set_header_if_absent(
71        &mut self,
72        name: impl TryInto<HeaderName>,
73        value: impl TryInto<HeaderValue>,
74    ) -> Result<(), ApigateError> {
75        let name = name
76            .try_into()
77            .map_err(|_| ApigateError::bad_request("invalid header name"))?;
78        if self.parts.headers.contains_key(&name) {
79            return Ok(());
80        }
81
82        let value = value
83            .try_into()
84            .map_err(|_| ApigateError::bad_request("invalid header value"))?;
85
86        self.parts.headers.insert(name, value);
87        Ok(())
88    }
89
90    pub fn remove_header(&mut self, name: &str) {
91        self.parts.headers.remove(name);
92    }
93
94    pub fn extensions(&self) -> &http::Extensions {
95        &self.parts.extensions
96    }
97
98    pub fn extensions_mut(&mut self) -> &mut http::Extensions {
99        &mut self.parts.extensions
100    }
101
102    pub async fn extract_path<T>(&mut self) -> Result<T, ApigateError>
103    where
104        T: Send,
105        axum::extract::Path<T>: FromRequestParts<()>,
106    {
107        axum::extract::Path::<T>::from_request_parts(self.parts, &())
108            .await
109            .map(|p| p.0)
110            .map_err(|_| ApigateError::bad_request("invalid path parameters"))
111    }
112}