spin_contrib_http/
response.rs

1use anyhow::Result;
2
3use spin_sdk::http::Response;
4
5/// Returns a `Result<spin_sdk::http::Response>` representing a redirect to the provided URL
6/// with the provided status code and Location header
7///
8/// # Arguments
9///
10/// * `url` - The URL to redirect to
11/// * `permanent` - Whether or not the redirect should be permanent
12///
13/// # Example
14/// ```rust
15/// use anyhow::Result;
16/// use spin_sdk::{
17///  http::{Request, Response},
18/// };  
19/// use spin_contrib_http::response::redirect;
20///
21/// pub fn handler(req: Request) -> Result<Response> {
22///   let target = "https://example.com";
23///   let permanent = false;
24///   redirect(target, permanent)
25/// }
26/// ```
27pub fn redirect(url: &str, permanent: bool) -> Result<Response> {
28    let mut status_code = http::StatusCode::TEMPORARY_REDIRECT;
29    if permanent {
30        status_code = http::StatusCode::PERMANENT_REDIRECT;
31    }
32    Ok(Response::builder()
33        .status(status_code)
34        .header(http::header::LOCATION.as_str(), url)
35        .body(())
36        .build())
37}
38
39/// Returns a `Result<spin_sdk::http::Response>` representing a 400 Bad Request
40///
41/// # Example
42/// ```rust
43/// use anyhow::Result;
44/// use spin_sdk::{
45///  http::{Request, Response},
46/// };
47/// use spin_contrib_http::response::bad_request;  
48///
49/// pub fn handler(req: Request) -> Result<Response> {
50///   bad_request()
51/// }
52/// ```
53pub fn bad_request() -> Result<Response> {
54    create_response(http::StatusCode::BAD_REQUEST)
55}
56
57/// Returns a `Result<spin_sdk::http::Response>` representing a 204 No Content
58///
59/// # Example
60/// ```rust
61/// use anyhow::Result;
62/// use spin_sdk::{
63///  http::{Request, Response},
64/// };  
65/// use spin_contrib_http::response::no_content;
66///
67/// pub fn handler(req: Request) -> Result<Response> {
68///  no_content()
69/// }
70/// ```
71pub fn no_content() -> Result<Response> {
72    create_response(http::StatusCode::NO_CONTENT)
73}
74
75/// Returns a `Result<spin_sdk::http::Response>` with desired status code
76///
77/// # Arguments
78///
79/// * `code` - The desired status code
80///
81/// # Example
82/// ```rust
83/// use anyhow::Result;
84/// use spin_sdk::{
85///  http::{Request, Response},
86/// };  
87/// use spin_contrib_http::response::status_code;
88///
89/// pub fn handler(req: Request) -> Result<Response> {
90///   status_code(http::StatusCode::OK)
91/// }
92/// ```
93pub fn status_code(status_code: http::StatusCode) -> Result<Response> {
94    create_response(status_code)
95}
96
97fn create_response(status_code: http::StatusCode) -> Result<Response> {
98    Ok(Response::new(status_code, ()))
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104
105    #[test]
106    fn no_content_should_set_status_code_to_204() {
107        let sut = no_content().unwrap();
108        assert_eq!(sut.status(), &http::StatusCode::NO_CONTENT.as_u16());
109    }
110
111    #[test]
112    fn bad_request_should_set_status_code_to_400() {
113        let sut = bad_request().unwrap();
114        assert_eq!(sut.status(), &http::StatusCode::BAD_REQUEST.as_u16());
115    }
116
117    #[test]
118    fn redirect_should_set_status_code_307_for_temporary() {
119        let sut = redirect("http://localhost:3000", false).unwrap();
120        assert_eq!(sut.status(), &http::StatusCode::TEMPORARY_REDIRECT.as_u16());
121    }
122
123    #[test]
124    fn redirect_should_set_status_code_302_for_permanent() {
125        let sut = redirect("http://localhost:3000", true).unwrap();
126        assert_eq!(sut.status(), &http::StatusCode::PERMANENT_REDIRECT.as_u16());
127    }
128
129    #[test]
130    fn redirect_should_set_location_header() {
131        let target = "http://localhost:3000";
132        let sut_permanent = redirect(target, true).unwrap();
133        let actual_permanent = sut_permanent
134            .header(http::header::LOCATION.as_str())
135            .expect("Header LOCATION not present")
136            .as_str()
137            .expect("Could not convert value to str");
138        assert_eq!(actual_permanent, target);
139
140        let sut_temp = redirect(target, false).unwrap();
141        let actual_temp = sut_temp
142            .header(http::header::LOCATION.as_str())
143            .expect("Header LOCATION not present")
144            .as_str()
145            .expect("Could not convert value to str");
146        assert_eq!(actual_temp, target);
147    }
148}