1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use bytes::Bytes;
use http::HeaderMap;
use http_body_util::BodyExt;
use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::server::{NgynContext, NgynResponse, Transformer};

#[derive(Serialize, Deserialize)]
/// Responses are hard to manage, especially when they are not standardized.
/// This is why Ngyn, by default, provides a json response format.
///
/// The json response format is a JSON object with two keys: `data` and `error`.
/// This would ideally make your responses more predictable and easier to manage.
/// A valid response would look like:
/// ```json
/// {
///    "data": {
///       "key": "value"
///   },
///  "error": null
/// }
/// ```
/// A valid error response would look like:
/// ```json
/// {
///   "data": null,
///  "error": {
///    "status": 404,
///    "message": "Not Found"
///   }
/// }
/// ```
/// The `data` key is used to store the response data, while the `error` key is used to store error data.
/// Both keys are optional, but at least one of them should be present.
///
///
/// ### How to create a json response?
/// Ngyn provides an implementation on [`JsonResult`] to convert it to a json response.
/// This means anytime you make use of a `JsonResult` in your controlled routes, it will be converted to a json response.
///
/// #### Example
/// ```rust ignore
/// use ngyn::prelude::*;
///
/// #[controller]
/// struct MyController;
///
/// #[routes]
/// impl MyController {
///    #[get("/")]
///   async fn get(&self, cx: &mut NgynContext) -> Result<Vec<u8>, ()> {
///    let data = vec![1, 2, 3];
///    Ok(data)
///   }
/// }
/// ```
pub struct JsonResponse<D: Serialize, E: Serialize> {
    data: Option<D>,
    error: Option<E>,
}

impl<D: Serialize, E: Serialize> JsonResponse<D, E> {
    /// Creates a new json response.
    pub fn new(data: Option<D>, error: Option<E>) -> Self {
        Self { data, error }
    }

    /// Returns the data.
    pub fn data(&self) -> Option<&D> {
        self.data.as_ref()
    }

    /// Returns the error data.
    pub fn error(&self) -> Option<&E> {
        self.error.as_ref()
    }
}

/// A shorthand for a json result.
///
/// This is useful when you want to return a json response.
/// It is a type alias for a [`Result`] with a [`Value`] as the `ok` and `error` type.
///
/// ### Example
///
/// ```rust ignore
/// use ngyn::prelude::*;
///
/// #[controller]
/// struct MyController;
///
/// #[routes]
/// impl MyController {
///    #[get("/")]
///   async fn get(&self, cx: &mut NgynContext) -> JsonResult {
///     let data = json!({ "key": "value" });
///     Ok(data)
///   }
/// }
/// ```
pub type JsonResult = Result<Value, Value>;

impl<'a> Transformer<'a> for &'a NgynResponse {
    fn transform(_cx: &'a mut NgynContext, res: &'a mut NgynResponse) -> Self {
        res
    }
}

impl<'a> Transformer<'a> for &'a mut NgynResponse {
    fn transform(_cx: &'a mut NgynContext, res: &'a mut NgynResponse) -> Self {
        res
    }
}

/// A shorthand for transforming a `HeaderMap` reference.
///
/// This is useful when you need to access the headers of a response.
impl<'a> Transformer<'a> for &'a HeaderMap {
    fn transform(_cx: &'a mut NgynContext, res: &'a mut NgynResponse) -> Self {
        res.headers()
    }
}

/// A shorthand for transforming a mutable `HeaderMap` reference.
///
/// This is useful when you want to add or remove headers from a response.
impl<'a> Transformer<'a> for &'a mut HeaderMap {
    fn transform(_cx: &'a mut NgynContext, res: &'a mut NgynResponse) -> Self {
        res.headers_mut()
    }
}

pub trait PeekBytes {
    #[allow(async_fn_in_trait)]
    /// Peeks the bytes of a valid ngyn response body.
    ///
    /// You can use this to read the bytes of a response body without consuming it(Well, we make it look like we don't).
    async fn peek_bytes(&mut self, f: impl FnMut(&Bytes));
}

impl PeekBytes for NgynResponse {
    async fn peek_bytes(&mut self, mut f: impl FnMut(&Bytes)) {
        let frame = self.frame().await;
        if let Some(Ok(frame)) = frame {
            if let Ok(bytes) = frame.into_data() {
                f(&bytes);
                // body has been read, so we need to set it back
                *self.body_mut() = bytes.into();
            }
        }
    }
}