Skip to main content

highnoon/
responder.rs

1use crate::response::Response;
2use crate::Result;
3use hyper::{Body, StatusCode};
4use serde::Serialize;
5
6/// This trait is implemented for all the common types you can return from an endpoint
7///
8/// It's also implemented for `Response` and `hyper::Response` for compatibility.
9/// There is an implementation for `Result<R> where R: Responder` which allows fallible
10/// functions to be used as endpoints
11///
12/// ```
13/// use highnoon::{Request, Responder, Json, StatusCode};
14///
15/// fn example_1(_: Request<()>) -> impl Responder {
16///     // return status code
17///     StatusCode::NOT_FOUND
18/// }
19///
20/// fn example_2(_: Request<()>) -> impl Responder {
21///     // return strings (&str or String)
22///     "Hello World"
23/// }
24///
25/// fn example_3(_: Request<()>) -> impl Responder {
26///     // return status code with data
27///     (StatusCode::NOT_FOUND, "Not found!")
28/// }
29///
30/// fn example_4(_: Request<()>) -> impl Responder {
31///     // return JSON data - for any type implementing `serde::Serialize`
32///     Json(vec![1, 2, 3])
33/// }
34///
35/// fn example_5(_: Request<()>) -> highnoon::Result<impl Responder> {
36///     // fallible functions too
37///     // (also works the return type as `impl Responder` as long as Rust can infer
38///     // the function returns `highnoon::Result`)
39///     Ok((StatusCode::CONFLICT, "Already Exists"))
40/// }
41/// ```
42
43pub trait Responder {
44    fn into_response(self) -> Result<Response>;
45}
46
47impl Responder for StatusCode {
48    fn into_response(self) -> Result<Response> {
49        Ok(Response::status(self))
50    }
51}
52
53impl Responder for String {
54    fn into_response(self) -> Result<Response> {
55        Ok(Response::ok().body(self))
56    }
57}
58
59impl Responder for &str {
60    fn into_response(self) -> Result<Response> {
61        Ok(Response::ok().body(self.to_owned()))
62    }
63}
64
65impl Responder for &[u8] {
66    fn into_response(self) -> Result<Response> {
67        Ok(Response::ok().body(self.to_vec()))
68    }
69}
70
71impl Responder for Vec<u8> {
72    fn into_response(self) -> Result<Response> {
73        Ok(Response::ok().body(self))
74    }
75}
76
77impl<R: Responder> Responder for (StatusCode, R) {
78    fn into_response(self) -> Result<Response> {
79        let mut resp = self.1.into_response()?;
80        resp.set_status(self.0);
81        Ok(resp)
82    }
83}
84
85/// Returns `StatusCode::NotFound` for `None`, and the inner value for `Some`
86impl<R: Responder> Responder for Option<R> {
87    fn into_response(self) -> Result<Response> {
88        match self {
89            None => StatusCode::NOT_FOUND.into_response(),
90            Some(r) => r.into_response(),
91        }
92    }
93}
94
95/// A Wrapper to return a JSON payload. This can be wrapped over any `serde::Serialize` type.
96/// ```
97/// use highnoon::{Request, Responder, Json};
98/// fn returns_json(_: Request<()>) -> impl Responder {
99///     Json(vec!["an", "array"])
100/// }
101/// ```
102pub struct Json<T: Serialize>(pub T);
103
104impl<T: Serialize> Responder for Json<T> {
105    fn into_response(self) -> Result<Response> {
106        Response::ok().json(self.0)
107    }
108}
109
110/// A Wrapper to return Form data. This can be wrapped over any `serde::Serialize` type.
111pub struct Form<T: Serialize>(pub T);
112
113impl<T: Serialize> Responder for Form<T> {
114    fn into_response(self) -> Result<Response> {
115        Response::ok().form(self.0)
116    }
117}
118
119/// Identity implementation
120impl Responder for Response {
121    fn into_response(self) -> Result<Response> {
122        Ok(self)
123    }
124}
125
126/// Compatibility with the inner hyper::Response
127impl Responder for hyper::Response<Body> {
128    fn into_response(self) -> Result<Response> {
129        Ok(self.into())
130    }
131}
132
133impl<R: Responder> Responder for Result<R> {
134    fn into_response(self) -> Result<Response> {
135        self.and_then(|r| r.into_response())
136    }
137}