zino_http/response/
mod.rs

1//! Constructing responses and rejections.
2
3use crate::{
4    helper,
5    request::RequestContext,
6    timing::{ServerTiming, TimingMetric},
7};
8use bytes::Bytes;
9use etag::EntityTag;
10use http::{HeaderMap, HeaderName};
11use serde::Serialize;
12use std::{
13    marker::PhantomData,
14    mem,
15    time::{Duration, Instant},
16};
17use zino_core::{
18    JsonValue, SharedString, Uuid, error::Error, extension::JsonValueExt, trace::TraceContext,
19    validation::Validation,
20};
21use zino_storage::NamedFile;
22
23#[cfg(feature = "inertia")]
24use crate::inertia::InertiaPage;
25
26#[cfg(feature = "cookie")]
27use cookie::Cookie;
28
29mod rejection;
30mod response_code;
31mod webhook;
32
33pub use rejection::{ExtractRejection, Rejection};
34pub use response_code::ResponseCode;
35pub use webhook::WebHook;
36
37/// An HTTP status code for http v0.2.
38#[cfg(feature = "http02")]
39pub type StatusCode = http02::StatusCode;
40
41/// An HTTP status code.
42#[cfg(not(feature = "http02"))]
43pub type StatusCode = http::StatusCode;
44
45/// A function pointer of transforming the response data.
46pub type DataTransformer = fn(data: &JsonValue) -> Result<Bytes, Error>;
47
48/// An HTTP response.
49#[derive(Debug, Clone, Serialize)]
50#[serde(rename_all = "snake_case")]
51pub struct Response<S: ResponseCode> {
52    /// A URI reference that identifies the problem type.
53    #[serde(rename = "type")]
54    #[serde(skip_serializing_if = "Option::is_none")]
55    type_uri: Option<SharedString>,
56    /// A short, human-readable summary of the problem type.
57    #[serde(skip_serializing_if = "Option::is_none")]
58    title: Option<SharedString>,
59    /// Status code.
60    #[serde(rename = "status")]
61    status_code: u16,
62    /// Error code.
63    #[serde(rename = "error")]
64    #[serde(skip_serializing_if = "Option::is_none")]
65    error_code: Option<S::ErrorCode>,
66    /// Business code.
67    #[serde(rename = "code")]
68    #[serde(skip_serializing_if = "Option::is_none")]
69    business_code: Option<S::BusinessCode>,
70    /// A human-readable explanation specific to this occurrence of the problem.
71    #[serde(skip_serializing_if = "Option::is_none")]
72    detail: Option<SharedString>,
73    /// A URI reference that identifies the specific occurrence of the problem.
74    #[serde(skip_serializing_if = "Option::is_none")]
75    instance: Option<SharedString>,
76    /// Indicates the response is successful or not.
77    success: bool,
78    /// A context-specific descriptive message for successful response.
79    #[serde(skip_serializing_if = "Option::is_none")]
80    message: Option<SharedString>,
81    /// Start time.
82    #[serde(skip)]
83    start_time: Instant,
84    /// Request ID.
85    #[serde(skip_serializing_if = "Uuid::is_nil")]
86    request_id: Uuid,
87    /// JSON data.
88    #[serde(rename = "data")]
89    #[serde(skip_serializing_if = "JsonValue::is_null")]
90    json_data: JsonValue,
91    /// Bytes data.
92    #[serde(skip)]
93    bytes_data: Bytes,
94    /// Transformer of the response data.
95    #[serde(skip)]
96    data_transformer: Option<DataTransformer>,
97    /// Content type.
98    #[serde(skip)]
99    content_type: Option<SharedString>,
100    /// Trace context.
101    #[serde(skip)]
102    trace_context: Option<TraceContext>,
103    /// Server timing.
104    #[serde(skip)]
105    server_timing: ServerTiming,
106    /// Custom headers.
107    #[serde(skip)]
108    headers: HeaderMap<String>,
109    /// Phantom type of response code.
110    #[serde(skip)]
111    phantom: PhantomData<S>,
112}
113
114impl<S: ResponseCode> Response<S> {
115    /// Creates a new instance.
116    pub fn new(code: S) -> Self {
117        let success = code.is_success();
118        let message = code.message();
119        let mut res = Self {
120            type_uri: code.type_uri(),
121            title: code.title(),
122            status_code: code.status_code(),
123            error_code: code.error_code(),
124            business_code: code.business_code(),
125            detail: None,
126            instance: None,
127            success,
128            message: None,
129            start_time: Instant::now(),
130            request_id: Uuid::nil(),
131            json_data: JsonValue::Null,
132            bytes_data: Bytes::new(),
133            data_transformer: None,
134            content_type: None,
135            trace_context: None,
136            server_timing: ServerTiming::new(),
137            headers: HeaderMap::default(),
138            phantom: PhantomData,
139        };
140        if success {
141            res.message = message;
142        } else {
143            res.detail = message;
144        }
145        res
146    }
147
148    /// Creates a new instance with the request context.
149    pub fn with_context<Ctx: RequestContext>(code: S, ctx: &Ctx) -> Self {
150        let success = code.is_success();
151        let message = code.message();
152        let mut res = Self {
153            type_uri: code.type_uri(),
154            title: code.title(),
155            status_code: code.status_code(),
156            error_code: code.error_code(),
157            business_code: code.business_code(),
158            detail: None,
159            instance: (!success).then(|| ctx.instance().into()),
160            success,
161            message: None,
162            start_time: ctx.start_time(),
163            request_id: ctx.request_id(),
164            json_data: JsonValue::Null,
165            bytes_data: Bytes::new(),
166            data_transformer: None,
167            content_type: None,
168            trace_context: None,
169            server_timing: ServerTiming::new(),
170            headers: HeaderMap::default(),
171            phantom: PhantomData,
172        };
173        if success {
174            res.message = message;
175        } else {
176            res.detail = message;
177        }
178        res.trace_context = Some(ctx.new_trace_context());
179        res
180    }
181
182    /// Provides the request context for the response.
183    pub fn context<Ctx: RequestContext>(mut self, ctx: &Ctx) -> Self {
184        self.instance = (!self.is_success()).then(|| ctx.instance().into());
185        self.start_time = ctx.start_time();
186        self.request_id = ctx.request_id();
187        self.trace_context = Some(ctx.new_trace_context());
188        self
189    }
190
191    /// Renders a template with the data and sets it as the reponse.
192    #[cfg(feature = "view")]
193    pub fn render<T: Serialize>(mut self, template_name: &str, data: T) -> Self {
194        let result = serde_json::to_value(data)
195            .map_err(|err| err.into())
196            .and_then(|mut value| {
197                if let Some(data) = value.as_object_mut() {
198                    let mut map = zino_core::Map::new();
199                    map.append(data);
200                    crate::view::render(template_name, map)
201                } else {
202                    Err(zino_core::warn!("invalid template data"))
203                }
204            });
205        match result {
206            Ok(content) => {
207                self.json_data = content.into();
208                self.bytes_data = Bytes::new();
209                self.content_type = Some("text/html; charset=utf-8".into());
210            }
211            Err(err) => {
212                let code = S::INTERNAL_SERVER_ERROR;
213                self.type_uri = code.type_uri();
214                self.title = code.title();
215                self.status_code = code.status_code();
216                self.error_code = code.error_code();
217                self.business_code = code.business_code();
218                self.success = false;
219                self.detail = Some(err.to_string().into());
220                self.message = None;
221                self.json_data = JsonValue::Null;
222                self.bytes_data = Bytes::new();
223            }
224        }
225        self
226    }
227
228    /// Sets the response code.
229    pub fn set_code(&mut self, code: S) {
230        let success = code.is_success();
231        let message = code.message();
232        self.type_uri = code.type_uri();
233        self.title = code.title();
234        self.status_code = code.status_code();
235        self.error_code = code.error_code();
236        self.business_code = code.business_code();
237        self.success = success;
238        if success {
239            self.detail = None;
240            self.message = message;
241        } else {
242            self.detail = message;
243            self.message = None;
244        }
245    }
246
247    /// Sets the status code.
248    #[inline]
249    pub fn set_status_code(&mut self, status_code: impl Into<u16>) {
250        self.status_code = status_code.into();
251    }
252
253    /// Sets the error code.
254    #[inline]
255    pub fn set_error_code(&mut self, error_code: impl Into<S::ErrorCode>) {
256        self.error_code = Some(error_code.into());
257    }
258
259    /// Sets the bussiness code.
260    #[inline]
261    pub fn set_business_code(&mut self, business_code: impl Into<S::BusinessCode>) {
262        self.business_code = Some(business_code.into());
263    }
264
265    /// Sets a URI reference that identifies the specific occurrence of the problem.
266    #[inline]
267    pub fn set_instance(&mut self, instance: impl Into<SharedString>) {
268        self.instance = Some(instance.into());
269    }
270
271    /// Sets the message. If the response is not successful,
272    /// it should be a human-readable explanation specific to this occurrence of the problem.
273    pub fn set_message(&mut self, message: impl Into<SharedString>) {
274        fn inner<S: ResponseCode>(res: &mut Response<S>, message: SharedString) {
275            if res.is_success() {
276                res.detail = None;
277                res.message = Some(message);
278            } else {
279                res.detail = Some(message);
280                res.message = None;
281            }
282        }
283        inner::<S>(self, message.into())
284    }
285
286    /// Sets the error message.
287    pub fn set_error_message(&mut self, error: impl Into<Error>) {
288        fn inner<S: ResponseCode>(res: &mut Response<S>, error: Error) {
289            let message = error.to_string().into();
290            if res.is_success() {
291                res.detail = None;
292                res.message = Some(message);
293            } else {
294                res.detail = Some(message);
295                res.message = None;
296            }
297        }
298        inner::<S>(self, error.into())
299    }
300
301    /// Sets the response data.
302    #[inline]
303    pub fn set_data<T: Serialize>(&mut self, data: &T) {
304        match serde_json::to_value(data) {
305            Ok(value) => {
306                self.json_data = value;
307                self.bytes_data = Bytes::new();
308            }
309            Err(err) => self.set_error_message(err),
310        }
311    }
312
313    /// Sets the JSON data.
314    #[inline]
315    pub fn set_json_data(&mut self, data: impl Into<JsonValue>) {
316        self.json_data = data.into();
317        self.bytes_data = Bytes::new();
318    }
319
320    /// Sets the bytes data.
321    #[inline]
322    pub fn set_bytes_data(&mut self, data: impl Into<Bytes>) {
323        self.json_data = JsonValue::Null;
324        self.bytes_data = data.into();
325    }
326
327    /// Sets the response data for the validation.
328    #[inline]
329    pub fn set_validation_data(&mut self, validation: Validation) {
330        self.json_data = validation.into_map().into();
331        self.bytes_data = Bytes::new();
332    }
333
334    /// Sets a transformer for the response data.
335    #[inline]
336    pub fn set_data_transformer(&mut self, transformer: DataTransformer) {
337        self.data_transformer = Some(transformer);
338    }
339
340    /// Sets the content type.
341    ///
342    /// # Note
343    ///
344    /// Currently, we have built-in support for the following values:
345    ///
346    /// - `application/json`
347    /// - `application/jsonlines`
348    /// - `application/octet-stream`
349    /// - `application/problem+json`
350    /// - `application/x-www-form-urlencoded`
351    /// - `text/csv`
352    /// - `text/html`
353    /// - `text/plain`
354    #[inline]
355    pub fn set_content_type(&mut self, content_type: impl Into<SharedString>) {
356        self.content_type = Some(content_type.into());
357    }
358
359    /// Sets the form data as the response body.
360    #[inline]
361    pub fn set_form_response(&mut self, data: impl Into<JsonValue>) {
362        fn inner<S: ResponseCode>(res: &mut Response<S>, data: JsonValue) {
363            res.set_json_data(data);
364            res.set_content_type("application/x-www-form-urlencoded");
365            res.set_data_transformer(|data| {
366                let mut bytes = Vec::new();
367                serde_qs::to_writer(&data, &mut bytes)?;
368                Ok(bytes.into())
369            });
370        }
371        inner::<S>(self, data.into())
372    }
373
374    /// Sets the JSON data as the response body.
375    #[inline]
376    pub fn set_json_response(&mut self, data: impl Into<JsonValue>) {
377        fn inner<S: ResponseCode>(res: &mut Response<S>, data: JsonValue) {
378            res.set_json_data(data);
379            res.set_data_transformer(|data| Ok(serde_json::to_vec(&data)?.into()));
380        }
381        inner::<S>(self, data.into())
382    }
383
384    /// Sets the JSON Lines data as the response body.
385    #[inline]
386    pub fn set_jsonlines_response(&mut self, data: impl Into<JsonValue>) {
387        fn inner<S: ResponseCode>(res: &mut Response<S>, data: JsonValue) {
388            res.set_json_data(data);
389            res.set_content_type("application/jsonlines; charset=utf-8");
390            res.set_data_transformer(|data| Ok(data.to_jsonlines(Vec::new())?.into()));
391        }
392        inner::<S>(self, data.into())
393    }
394
395    /// Sets the CSV data as the response body.
396    #[inline]
397    pub fn set_csv_response(&mut self, data: impl Into<JsonValue>) {
398        fn inner<S: ResponseCode>(res: &mut Response<S>, data: JsonValue) {
399            res.set_json_data(data);
400            res.set_content_type("text/csv; charset=utf-8");
401            res.set_data_transformer(|data| Ok(data.to_csv(Vec::new())?.into()));
402        }
403        inner::<S>(self, data.into())
404    }
405
406    /// Sets the plain text as the response body.
407    #[inline]
408    pub fn set_text_response(&mut self, data: impl Into<String>) {
409        self.set_json_data(data.into());
410        self.set_content_type("text/plain; charset=utf-8");
411    }
412
413    /// Sets the bytes data as the response body.
414    #[inline]
415    pub fn set_bytes_response(&mut self, data: impl Into<Bytes>) {
416        self.set_bytes_data(data);
417        self.set_content_type("application/octet-stream");
418    }
419
420    /// Sets the request ID.
421    #[inline]
422    pub(crate) fn set_request_id(&mut self, request_id: Uuid) {
423        self.request_id = request_id;
424    }
425
426    /// Sets the trace context from headers.
427    #[inline]
428    pub(crate) fn set_trace_context(&mut self, trace_context: Option<TraceContext>) {
429        self.trace_context = trace_context;
430    }
431
432    /// Sets the start time.
433    #[inline]
434    pub(crate) fn set_start_time(&mut self, start_time: Instant) {
435        self.start_time = start_time;
436    }
437
438    /// Sends a cookie to the user agent.
439    #[cfg(feature = "cookie")]
440    #[inline]
441    pub fn set_cookie(&mut self, cookie: &Cookie<'_>) {
442        self.insert_header("set-cookie", cookie.to_string());
443    }
444
445    /// Records a server timing metric entry.
446    pub fn record_server_timing(
447        &mut self,
448        name: impl Into<SharedString>,
449        description: impl Into<Option<SharedString>>,
450        duration: impl Into<Option<Duration>>,
451    ) {
452        fn inner<S: ResponseCode>(
453            res: &mut Response<S>,
454            name: SharedString,
455            description: Option<SharedString>,
456            duration: Option<Duration>,
457        ) {
458            let metric = TimingMetric::new(name, description, duration);
459            res.server_timing.push(metric);
460        }
461        inner::<S>(self, name.into(), description.into(), duration.into())
462    }
463
464    /// Inserts a custom header.
465    #[inline]
466    pub fn insert_header(&mut self, name: &'static str, value: impl ToString) {
467        self.headers
468            .insert(HeaderName::from_static(name), value.to_string());
469    }
470
471    /// Gets a custome header with the given name.
472    #[inline]
473    pub fn get_header(&self, name: &str) -> Option<&str> {
474        self.headers
475            .iter()
476            .find_map(|(key, value)| (key == name).then_some(value.as_str()))
477    }
478
479    /// Returns the status code as `u16`.
480    #[inline]
481    pub fn status_code(&self) -> u16 {
482        self.status_code
483    }
484
485    /// Returns the error code.
486    #[inline]
487    pub fn error_code(&self) -> Option<&S::ErrorCode> {
488        self.error_code.as_ref()
489    }
490
491    /// Returns the business code.
492    #[inline]
493    pub fn business_code(&self) -> Option<&S::BusinessCode> {
494        self.business_code.as_ref()
495    }
496
497    /// Returns `true` if the response is successful or `false` otherwise.
498    #[inline]
499    pub fn is_success(&self) -> bool {
500        self.success
501    }
502
503    /// Returns `true` if the response has a request context.
504    #[inline]
505    pub fn has_context(&self) -> bool {
506        self.trace_context.is_some() && !self.request_id.is_nil()
507    }
508
509    /// Returns the message.
510    #[inline]
511    pub fn message(&self) -> Option<&str> {
512        self.detail
513            .as_ref()
514            .or(self.message.as_ref())
515            .map(|s| s.as_ref())
516    }
517
518    /// Returns the request ID.
519    #[inline]
520    pub fn request_id(&self) -> Uuid {
521        self.request_id
522    }
523
524    /// Returns the trace ID.
525    #[inline]
526    pub fn trace_id(&self) -> Uuid {
527        if let Some(ref trace_context) = self.trace_context {
528            Uuid::from_u128(trace_context.trace_id())
529        } else {
530            Uuid::nil()
531        }
532    }
533
534    /// Returns the content type.
535    #[inline]
536    pub fn content_type(&self) -> &str {
537        self.content_type.as_deref().unwrap_or_else(|| {
538            if !self.bytes_data.is_empty() {
539                "application/octet-stream"
540            } else if self.is_success() {
541                "application/json; charset=utf-8"
542            } else {
543                "application/problem+json; charset=utf-8"
544            }
545        })
546    }
547
548    /// Returns a reference to the custom headers.
549    #[inline]
550    pub fn headers(&self) -> &HeaderMap<String> {
551        &self.headers
552    }
553
554    /// Returns a mutable reference to the custom headers.
555    #[inline]
556    pub fn headers_mut(&mut self) -> &mut HeaderMap<String> {
557        &mut self.headers
558    }
559
560    /// Returns the trace context in the form `(traceparent, tracestate)`.
561    pub fn trace_context(&self) -> (String, String) {
562        if let Some(ref trace_context) = self.trace_context {
563            (trace_context.traceparent(), trace_context.tracestate())
564        } else {
565            let mut trace_context = TraceContext::new();
566            trace_context.record_trace_state();
567            (trace_context.traceparent(), trace_context.tracestate())
568        }
569    }
570
571    /// Returns the server timing.
572    #[inline]
573    pub fn server_timing(&self) -> String {
574        self.server_timing.to_string()
575    }
576
577    /// Reads the response into a byte buffer.
578    pub fn read_bytes(&mut self) -> Result<Bytes, Error> {
579        let has_bytes_data = !self.bytes_data.is_empty();
580        let has_json_data = !self.json_data.is_null();
581        let bytes_opt = if has_bytes_data {
582            Some(mem::take(&mut self.bytes_data))
583        } else if has_json_data {
584            if let Some(transformer) = self.data_transformer.as_ref() {
585                Some(transformer(&self.json_data)?)
586            } else {
587                None
588            }
589        } else {
590            None
591        };
592        if let Some(bytes) = bytes_opt {
593            let etag = EntityTag::from_data(&bytes);
594            self.insert_header("x-etag", etag);
595            return Ok(bytes);
596        }
597
598        let content_type = self.content_type();
599        let (bytes, etag_opt) = if crate::helper::check_json_content_type(content_type) {
600            let (capacity, etag_opt) = if has_json_data {
601                let data = serde_json::to_vec(&self.json_data)?;
602                let etag = EntityTag::from_data(&data);
603                (data.len() + 128, Some(etag))
604            } else {
605                (128, None)
606            };
607            let mut bytes = Vec::with_capacity(capacity);
608            serde_json::to_writer(&mut bytes, &self)?;
609            (bytes, etag_opt)
610        } else if has_json_data {
611            let bytes = if content_type.starts_with("text/csv") {
612                self.json_data.to_csv(Vec::new())?
613            } else if content_type.starts_with("application/jsonlines") {
614                self.json_data.to_jsonlines(Vec::new())?
615            } else {
616                let text = if let JsonValue::String(s) = &mut self.json_data {
617                    mem::take(s)
618                } else {
619                    self.json_data.to_string()
620                };
621                text.into_bytes()
622            };
623            (bytes, None)
624        } else {
625            (Vec::new(), None)
626        };
627        let etag = etag_opt.unwrap_or_else(|| EntityTag::from_data(&bytes));
628        self.insert_header("x-etag", etag);
629        Ok(bytes.into())
630    }
631
632    /// Gets the response time.
633    ///
634    /// # Note
635    ///
636    /// It should only be called when the response will finish.
637    pub fn response_time(&self) -> Duration {
638        let start_time = self.start_time;
639        #[cfg(feature = "metrics")]
640        {
641            let labels = [("status_code", self.status_code().to_string())];
642            metrics::gauge!("zino_http_requests_in_flight").decrement(1.0);
643            metrics::counter!("zino_http_responses_total", &labels).increment(1);
644            metrics::histogram!("zino_http_requests_duration_seconds", &labels,)
645                .record(start_time.elapsed().as_secs_f64());
646        }
647        start_time.elapsed()
648    }
649
650    /// Sends a file to the client.
651    pub fn send_file(&mut self, file: NamedFile) {
652        let mut displayed_inline = false;
653        if let Some(content_type) = file.content_type() {
654            displayed_inline = helper::displayed_inline(content_type);
655            self.set_content_type(content_type.to_string());
656        }
657        if !displayed_inline {
658            if let Some(file_name) = file.file_name() {
659                self.insert_header(
660                    "content-disposition",
661                    format!(r#"attachment; filename="{file_name}""#),
662                );
663            }
664        }
665        self.insert_header("etag", file.etag());
666        self.set_bytes_data(Bytes::from(file));
667    }
668
669    /// Sends an Inertia page to the client.
670    #[cfg(feature = "inertia")]
671    pub fn send_inertia_page(&mut self, mut page: InertiaPage) {
672        if page.version().is_empty() {
673            page.set_version(zino_core::datetime::DateTime::current_timestamp().to_string());
674        }
675        self.insert_header("vary", "x-inertia");
676        self.insert_header("x-insertia", true);
677        if let Some(url) = page.redirect_url() {
678            self.insert_header("x-inertia-location", url);
679        } else {
680            self.set_json_response(page.into_json_response());
681        }
682    }
683
684    /// Emits the response for the request.
685    pub fn emit<Ctx: RequestContext>(mut self, ctx: &Ctx) -> Self {
686        if ctx
687            .get_header("prefer")
688            .is_some_and(|s| s.split(';').any(|p| p.trim() == "return=data-only"))
689        {
690            self.set_data_transformer(|data| Ok(serde_json::to_vec(&data)?.into()));
691        }
692        #[cfg(feature = "inertia")]
693        if self.get_header("x-inertia").is_none()
694            && ctx.get_header("x-inertia-partial-component").is_some()
695        {
696            match InertiaPage::partial_reload(ctx) {
697                Ok(mut page) => {
698                    if let JsonValue::Object(data) = &mut self.json_data {
699                        page.append_props(data);
700                    }
701                    self.send_inertia_page(page);
702                }
703                Err(err) => self.set_error_message(err),
704            }
705        }
706        self
707    }
708
709    /// Consumes `self` and returns the custom headers.
710    pub fn finalize(mut self) -> HeaderMap<String> {
711        let request_id = self.request_id();
712        if !request_id.is_nil() {
713            self.insert_header("x-request-id", request_id.to_string());
714        }
715
716        let (traceparent, tracestate) = self.trace_context();
717        self.insert_header("traceparent", traceparent);
718        self.insert_header("tracestate", tracestate);
719
720        let duration = self.response_time();
721        self.record_server_timing("total", None, Some(duration));
722        self.insert_header("server-timing", self.server_timing());
723        self.headers
724    }
725}
726
727impl Response<StatusCode> {
728    /// Constructs a new response with status `200 OK`.
729    #[inline]
730    pub fn ok() -> Self {
731        Response::new(StatusCode::OK)
732    }
733
734    /// Constructs a new response with status `201 Created`.
735    #[inline]
736    pub fn created() -> Self {
737        Response::new(StatusCode::CREATED)
738    }
739
740    /// Constructs a new response with status `400 Bad Request`.
741    #[inline]
742    pub fn bad_request() -> Self {
743        Response::new(StatusCode::BAD_REQUEST)
744    }
745
746    /// Constructs a new response with status `401 Unauthorized`.
747    #[inline]
748    pub fn unauthorized() -> Self {
749        Response::new(StatusCode::UNAUTHORIZED)
750    }
751
752    /// Constructs a new response with status `403 Forbidden`.
753    #[inline]
754    pub fn forbidden() -> Self {
755        Response::new(StatusCode::FORBIDDEN)
756    }
757
758    /// Constructs a new response with status `404 Not Found`.
759    #[inline]
760    pub fn not_found() -> Self {
761        Response::new(StatusCode::NOT_FOUND)
762    }
763
764    /// Constructs a new response with status `405 Method Not Allowed`.
765    #[inline]
766    pub fn method_not_allowed() -> Self {
767        Response::new(StatusCode::METHOD_NOT_ALLOWED)
768    }
769
770    /// Constructs a new response with status `409 Conflict`.
771    #[inline]
772    pub fn conflict() -> Self {
773        Response::new(StatusCode::CONFLICT)
774    }
775
776    /// Constructs a new response with status `500 Internal Server Error`.
777    #[inline]
778    pub fn internal_server_error() -> Self {
779        Response::new(StatusCode::INTERNAL_SERVER_ERROR)
780    }
781
782    /// Constructs a new response with status `503 Service Unavailable`.
783    #[inline]
784    pub fn service_unavailable() -> Self {
785        Response::new(StatusCode::SERVICE_UNAVAILABLE)
786    }
787}
788
789impl<S: ResponseCode> Default for Response<S> {
790    #[inline]
791    fn default() -> Self {
792        Self::new(S::OK)
793    }
794}
795
796impl<S: ResponseCode> From<Validation> for Response<S> {
797    fn from(validation: Validation) -> Self {
798        if validation.is_success() {
799            Self::new(S::OK)
800        } else {
801            let mut res = Self::new(S::BAD_REQUEST);
802            res.set_validation_data(validation);
803            res
804        }
805    }
806}