http_kit/response.rs
1//! HTTP response implementation.
2//!
3//! This module provides the [`Response`] type which represents an HTTP response including
4//! headers, status code, version, and body. It offers comprehensive methods for:
5//!
6//! - **Response creation** - Building responses with different status codes and body types
7//! - **Header manipulation** - Setting, getting, and modifying HTTP headers
8//! - **Body handling** - Working with various body formats (bytes, strings, JSON, form data, files)
9//! - **Extensions** - Storing custom application data associated with the response
10//! - **Content types** - Automatic MIME type detection and content type headers
11//!
12//! The [`Response`] type integrates seamlessly with the body system and provides convenient
13//! conversions from common Rust types like `String`, `Vec<u8>`, `Bytes`, etc.
14//!
15//! # Examples
16//!
17//! ## Basic Response Creation
18//!
19//! ```rust
20//! use http_kit::{Response, StatusCode};
21//!
22//! // Simple text response
23//! let response = Response::new(StatusCode::OK, "Hello, World!");
24//!
25//! // Empty response
26//! let empty = Response::empty();
27//!
28//! // Response with custom status
29//! let not_found = Response::new(404, "Page not found");
30//! ```
31//!
32//! ## Working with Headers
33//!
34//! ```rust
35//! use http_kit::Response;
36//!
37//! let response = Response::new(200, "OK")
38//! .header(http::header::CONTENT_TYPE, "text/plain")
39//! .header(http::header::SERVER, "http-kit/1.0");
40//! ```
41//!
42//! ## JSON Responses
43//!
44//! ```rust
45//! # #[cfg(feature = "json")]
46//! # {
47//! use http_kit::Response;
48//! use serde::Serialize;
49//!
50//! #[derive(Serialize)]
51//! struct User { name: String, id: u32 }
52//!
53//! let user = User { name: "Alice".to_string(), id: 123 };
54//! let response = Response::empty().json(&user)?;
55//! # }
56//! # Ok::<(), serde_json::Error>(())
57//! ```
58//!
59//! ## File Responses
60//!
61//! ```rust,no_run
62//! # #[cfg(feature = "fs")]
63//! # {
64//! use http_kit::Response;
65//!
66//! # async fn example() -> Result<(), std::io::Error> {
67//! let response = Response::empty().file("static/index.html").await?;
68//! // Content-Type header will be set automatically based on file extension
69//! # Ok(())
70//! # }
71//! # }
72//! ```
73use core::fmt::Debug;
74
75use crate::{body::BodyFrozen, Body, BodyError};
76use alloc::string::String;
77use alloc::vec::Vec;
78use bytes::Bytes;
79use bytestr::ByteStr;
80use http::{
81 header::{GetAll, HeaderName},
82 Extensions, HeaderMap, HeaderValue, StatusCode, Version,
83};
84
85/// The HTTP response parts.
86pub type ResponseParts = http::response::Parts;
87
88/// An HTTP response with status, headers, and body.
89///
90/// `Response` represents a complete HTTP response that can be constructed, modified,
91/// and sent back to clients. It provides comprehensive methods for working with all
92/// aspects of HTTP responses including:
93///
94/// - **Status codes** - Setting and querying HTTP status codes (200, 404, 500, etc.)
95/// - **Headers** - Managing HTTP headers for metadata, caching, content type, etc.
96/// - **Body content** - Handling response payloads in various formats
97/// - **HTTP version** - Specifying the HTTP protocol version
98/// - **Extensions** - Storing custom application data
99///
100/// The response type integrates with the body system to provide convenient methods
101/// for handling different content types like JSON, form data, files, and raw bytes.
102///
103/// # Examples
104///
105/// ## Creating Basic Responses
106///
107/// ```rust
108/// use http_kit::{Response, StatusCode};
109///
110/// // Success response with text
111/// let ok = Response::new(200, "Operation successful");
112///
113/// // Error response
114/// let error = Response::new(StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong");
115///
116/// // Empty response
117/// let empty = Response::empty();
118/// ```
119///
120/// ## Building Rich Responses
121///
122/// ```rust
123/// use http_kit::Response;
124///
125/// let response = Response::new(201, "Created")
126/// .header(http::header::LOCATION, "/api/users/123")
127/// .header(http::header::CONTENT_TYPE, "text/plain");
128/// ```
129///
130/// ## Working with Body Content
131///
132/// ```rust
133/// # async fn example() -> Result<(), http_kit::BodyError> {
134/// use http_kit::Response;
135///
136/// let mut response = Response::new(200, "Hello, world!");
137///
138/// // Read the body content
139/// let content = response.into_string().await?;
140/// assert_eq!(content, "Hello, world!");
141/// # Ok(())
142/// # }
143/// ```
144#[derive(Debug)]
145pub struct Response {
146 parts: ResponseParts,
147 body: Body,
148}
149
150impl From<http::Response<Body>> for Response {
151 fn from(response: http::Response<Body>) -> Self {
152 let (parts, body) = response.into_parts();
153 Self { parts, body }
154 }
155}
156
157impl From<Response> for http::Response<Body> {
158 fn from(response: Response) -> Self {
159 Self::from_parts(response.parts, response.body)
160 }
161}
162
163macro_rules! impl_response_from {
164 ($($ty:ty),*) => {
165 $(
166 impl From<$ty> for Response {
167 fn from(value: $ty) -> Self {
168 Self::new(StatusCode::OK, value)
169 }
170 }
171 )*
172 };
173}
174
175impl_response_from![ByteStr, String, Vec<u8>, Bytes, &str, &[u8]];
176
177impl Response {
178 /// Creates a new HTTP response with the specified status code and body.
179 ///
180 /// This is the primary constructor for building responses. The body can be any type
181 /// that converts to `Body`, including strings, byte vectors, and `Bytes` objects.
182 ///
183 /// # Arguments
184 ///
185 /// * `status` - The HTTP status code (or value convertible to `StatusCode`)
186 /// * `body` - The response body (any type convertible to `Body`)
187 ///
188 /// # Examples
189 ///
190 /// ```rust
191 /// use http_kit::{Response, StatusCode};
192 ///
193 /// // With numeric status code
194 /// let response = Response::new(200, "Success");
195 ///
196 /// // With StatusCode enum
197 /// let response = Response::new(StatusCode::CREATED, "Resource created");
198 ///
199 /// // With byte vector
200 /// let response = Response::new(200, vec![72, 101, 108, 108, 111]);
201 ///
202 /// // With string
203 /// let response = Response::new(200, "Hello, world!".to_string());
204 /// ```
205 pub fn new<S>(status: S, body: impl Into<Body>) -> Self
206 where
207 S: TryInto<StatusCode>,
208 S::Error: Debug,
209 {
210 let mut response: Self = http::Response::new(body.into()).into();
211 response.set_status(status.try_into().unwrap());
212 response
213 }
214
215 /// Creates an empty HTTP response with status 200 OK.
216 ///
217 /// This is a convenience method for creating responses that don't need body content,
218 /// such as successful operations that only need to indicate completion.
219 ///
220 /// # Examples
221 ///
222 /// ```rust
223 /// use http_kit::Response;
224 ///
225 /// let response = Response::empty();
226 /// assert_eq!(response.status(), http::StatusCode::OK);
227 /// ```
228 pub fn empty() -> Self {
229 Self::new(StatusCode::OK, Body::empty())
230 }
231
232 /// Returns the HTTP status code of this response.
233 ///
234 /// # Examples
235 ///
236 /// ```rust
237 /// use http_kit::{Response, StatusCode};
238 ///
239 /// let response = Response::new(404, "Not found");
240 /// assert_eq!(response.status(), StatusCode::NOT_FOUND);
241 /// ```
242 pub const fn status(&self) -> StatusCode {
243 self.parts.status
244 }
245 /// Returns a mutable reference to the HTTP status code.
246 ///
247 /// This allows direct modification of the status code.
248 ///
249 /// # Examples
250 ///
251 /// ```rust
252 /// use http_kit::{Response, StatusCode};
253 ///
254 /// let mut response = Response::empty();
255 /// *response.status_mut() = StatusCode::CREATED;
256 /// assert_eq!(response.status(), StatusCode::CREATED);
257 /// ```
258 pub fn status_mut(&mut self) -> &mut StatusCode {
259 &mut self.parts.status
260 }
261
262 /// Sets the HTTP status code for this response.
263 ///
264 /// # Arguments
265 ///
266 /// * `status` - The new status code
267 ///
268 /// # Examples
269 ///
270 /// ```rust
271 /// use http_kit::{Response, StatusCode};
272 ///
273 /// let mut response = Response::empty();
274 /// response.set_status(StatusCode::NOT_FOUND);
275 /// assert_eq!(response.status(), StatusCode::NOT_FOUND);
276 /// ```
277 pub fn set_status(&mut self, status: StatusCode) {
278 *self.status_mut() = status;
279 }
280
281 /// Returns the HTTP version for this response.
282 ///
283 /// # Examples
284 ///
285 /// ```rust
286 /// use http_kit::{Response, Version};
287 ///
288 /// let response = Response::empty();
289 /// // Default version is typically HTTP/1.1
290 /// assert_eq!(response.version(), Version::HTTP_11);
291 /// ```
292 pub const fn version(&self) -> Version {
293 self.parts.version
294 }
295
296 /// Returns a mutable reference to the HTTP version.
297 ///
298 /// This allows direct modification of the HTTP version.
299 ///
300 /// # Examples
301 ///
302 /// ```rust
303 /// use http_kit::{Response, Version};
304 ///
305 /// let mut response = Response::empty();
306 /// *response.version_mut() = Version::HTTP_2;
307 /// assert_eq!(response.version(), Version::HTTP_2);
308 /// ```
309 pub fn version_mut(&mut self) -> &mut Version {
310 &mut self.parts.version
311 }
312
313 /// Sets the HTTP version for this response.
314 ///
315 /// # Arguments
316 ///
317 /// * `version` - The HTTP version to use
318 ///
319 /// # Examples
320 ///
321 /// ```rust
322 /// use http_kit::{Response, Version};
323 ///
324 /// let mut response = Response::empty();
325 /// response.set_version(Version::HTTP_2);
326 /// assert_eq!(response.version(), Version::HTTP_2);
327 /// ```
328 pub fn set_version(&mut self, version: Version) {
329 *self.version_mut() = version;
330 }
331
332 /// Returns a reference to the HTTP headers.
333 ///
334 /// # Examples
335 ///
336 /// ```rust
337 /// use http_kit::Response;
338 ///
339 /// let response = Response::new(200, "OK")
340 /// .header(http::header::CONTENT_TYPE, "text/plain");
341 ///
342 /// let headers = response.headers();
343 /// assert!(headers.contains_key(http::header::CONTENT_TYPE));
344 /// ```
345 pub const fn headers(&self) -> &HeaderMap {
346 &self.parts.headers
347 }
348
349 /// Returns a mutable reference to the HTTP headers.
350 ///
351 /// This allows direct manipulation of the header map.
352 ///
353 /// # Examples
354 ///
355 /// ```rust
356 /// use http_kit::Response;
357 ///
358 /// let mut response = Response::empty();
359 /// response.headers_mut().insert(
360 /// http::header::CONTENT_TYPE,
361 /// "application/json".parse().unwrap()
362 /// );
363 /// ```
364 pub fn headers_mut(&mut self) -> &mut HeaderMap {
365 &mut self.parts.headers
366 }
367
368 /// Returns the first value for the given header name.
369 ///
370 /// If the header has multiple values, only the first one is returned.
371 /// Returns `None` if the header is not present.
372 ///
373 /// # Arguments
374 ///
375 /// * `name` - The header name to look up
376 ///
377 /// # Examples
378 ///
379 /// ```rust
380 /// use http_kit::Response;
381 ///
382 /// let response = Response::new(200, "OK")
383 /// .header(http::header::CONTENT_TYPE, "application/json");
384 ///
385 /// if let Some(content_type) = response.get_header(http::header::CONTENT_TYPE) {
386 /// assert_eq!(content_type, "application/json");
387 /// }
388 /// ```
389 pub fn get_header(&self, name: HeaderName) -> Option<&HeaderValue> {
390 self.headers().get(name)
391 }
392
393 /// Returns an iterator over all values for a given header name.
394 ///
395 /// This method retrieves all values associated with a header name, since
396 /// HTTP headers can have multiple values. The returned iterator will yield
397 /// each value in the order they were added.
398 ///
399 /// # Arguments
400 ///
401 /// * `name` - The header name to get values for
402 ///
403 /// # Examples
404 ///
405 /// ```rust
406 /// use http_kit::Response;
407 ///
408 /// let response = Response::new(200, "OK")
409 /// .header(http::header::SET_COOKIE, "session=123")
410 /// .header(http::header::SET_COOKIE, "theme=dark");
411 ///
412 /// for cookie in response.get_headers(http::header::SET_COOKIE) {
413 /// // Iterate over each Set-Cookie header value
414 /// }
415 /// ```
416 pub fn get_headers(&self, name: HeaderName) -> GetAll<'_, HeaderValue> {
417 self.headers().get_all(name)
418 }
419
420 /// Appends a header value without removing existing values.
421 ///
422 /// If a header with the same name already exists, the new value is added
423 /// alongside the existing values rather than replacing them.
424 ///
425 /// # Arguments
426 ///
427 /// * `name` - The header name
428 /// * `value` - The header value to append
429 ///
430 /// # Examples
431 ///
432 /// ```rust
433 /// use http_kit::Response;
434 ///
435 /// let mut response = Response::empty();
436 /// response.append_header(http::header::SET_COOKIE, "session=abc123".parse().unwrap());
437 /// response.append_header(http::header::SET_COOKIE, "theme=dark".parse().unwrap());
438 /// // Both cookies will be present in the response
439 /// ```
440 pub fn append_header(&mut self, name: HeaderName, value: HeaderValue) {
441 self.headers_mut().append(name, value);
442 }
443
444 /// Inserts a header value, replacing any existing values.
445 ///
446 /// If a header with the same name already exists, it is completely replaced
447 /// with the new value.
448 ///
449 /// # Arguments
450 ///
451 /// * `name` - The header name
452 /// * `value` - The header value
453 ///
454 /// # Returns
455 ///
456 /// Returns the previous header value if one existed.
457 ///
458 /// # Examples
459 ///
460 /// ```rust
461 /// use http_kit::Response;
462 ///
463 /// let mut response = Response::empty();
464 /// let old_value = response.insert_header(
465 /// http::header::SERVER,
466 /// "http-kit/1.0".parse().unwrap()
467 /// );
468 /// assert!(old_value.is_none());
469 ///
470 /// let old_value = response.insert_header(
471 /// http::header::SERVER,
472 /// "http-kit/2.0".parse().unwrap()
473 /// );
474 /// assert!(old_value.is_some());
475 /// ```
476 pub fn insert_header(&mut self, name: HeaderName, value: HeaderValue) -> Option<HeaderValue> {
477 self.headers_mut().insert(name, value)
478 }
479
480 /// Sets an HTTP header and returns the modified response.
481 ///
482 /// This is a builder-style method that allows method chaining. If you need to
483 /// modify an existing response, use [`insert_header`] instead.
484 ///
485 /// # Arguments
486 ///
487 /// * `name` - The header name
488 /// * `value` - The header value
489 ///
490 /// # Examples
491 ///
492 /// ```rust
493 /// use http_kit::Response;
494 ///
495 /// let response = Response::new(200, "OK")
496 /// .header(http::header::CONTENT_TYPE, "application/json")
497 /// .header(http::header::SERVER, "http-kit/1.0");
498 /// ```
499 ///
500 /// [`insert_header`]: Response::insert_header
501 pub fn header<V>(mut self, name: HeaderName, value: V) -> Self
502 where
503 V: TryInto<HeaderValue>,
504 V::Error: Debug,
505 {
506 self.insert_header(name, value.try_into().unwrap());
507 self
508 }
509
510 /// Returns a reference to the response extensions.
511 ///
512 /// Extensions provide a type-safe way to store additional data associated
513 /// with the response that doesn't fit into standard HTTP fields.
514 ///
515 /// # Examples
516 ///
517 /// ```rust
518 /// use http_kit::Response;
519 ///
520 /// let response = Response::empty();
521 /// let extensions = response.extensions();
522 /// // Check if a specific type is stored
523 /// let timing: Option<&u64> = extensions.get();
524 /// ```
525 pub const fn extensions(&self) -> &Extensions {
526 &self.parts.extensions
527 }
528
529 /// Returns a mutable reference to the response extensions.
530 ///
531 /// This allows modification of the extensions map.
532 ///
533 /// # Examples
534 ///
535 /// ```rust
536 /// use http_kit::Response;
537 ///
538 /// let mut response = Response::empty();
539 /// response.extensions_mut().insert(42u32);
540 /// ```
541 pub fn extensions_mut(&mut self) -> &mut Extensions {
542 &mut self.parts.extensions
543 }
544
545 /// Returns a reference to an extension of the specified type.
546 ///
547 /// # Type Parameters
548 ///
549 /// * `T` - The type to retrieve from extensions
550 ///
551 /// # Examples
552 ///
553 /// ```rust
554 /// use http_kit::Response;
555 ///
556 /// let mut response = Response::empty();
557 /// response.insert_extension(42u32);
558 ///
559 /// if let Some(value) = response.get_extension::<u32>() {
560 /// assert_eq!(*value, 42);
561 /// }
562 /// ```
563 pub fn get_extension<T: Send + Sync + 'static>(&self) -> Option<&T> {
564 self.extensions().get()
565 }
566
567 /// Returns a mutable reference to an extension of the specified type.
568 ///
569 /// # Type Parameters
570 ///
571 /// * `T` - The type to retrieve from extensions
572 ///
573 /// # Examples
574 ///
575 /// ```rust
576 /// use http_kit::Response;
577 ///
578 /// let mut response = Response::empty();
579 /// response.insert_extension(42u32);
580 ///
581 /// if let Some(value) = response.get_mut_extension::<u32>() {
582 /// *value = 100;
583 /// }
584 /// ```
585 pub fn get_mut_extension<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
586 self.extensions_mut().get_mut()
587 }
588
589 /// Removes and returns an extension of the specified type.
590 ///
591 /// # Type Parameters
592 ///
593 /// * `T` - The type to remove from extensions
594 ///
595 /// # Returns
596 ///
597 /// Returns the removed value if it existed, or `None` if it wasn't present.
598 ///
599 /// # Examples
600 ///
601 /// ```rust
602 /// use http_kit::Response;
603 ///
604 /// let mut response = Response::empty();
605 /// response.insert_extension(42u32);
606 ///
607 /// let removed = response.remove_extension::<u32>();
608 /// assert_eq!(removed, Some(42));
609 ///
610 /// let removed_again = response.remove_extension::<u32>();
611 /// assert_eq!(removed_again, None);
612 /// ```
613 pub fn remove_extension<T: Send + Sync + 'static>(&mut self) -> Option<T> {
614 self.extensions_mut().remove()
615 }
616
617 /// Inserts an extension value, returning any previous value of the same type.
618 ///
619 /// # Type Parameters
620 ///
621 /// * `T` - The type to insert into extensions
622 ///
623 /// # Arguments
624 ///
625 /// * `extension` - The value to insert
626 ///
627 /// # Returns
628 ///
629 /// Returns the previous value of the same type if one existed.
630 ///
631 /// # Examples
632 ///
633 /// ```rust
634 /// use http_kit::Response;
635 ///
636 /// let mut response = Response::empty();
637 ///
638 /// let old_value = response.insert_extension(42u32);
639 /// assert_eq!(old_value, None);
640 ///
641 /// let old_value = response.insert_extension(100u32);
642 /// assert_eq!(old_value, Some(42));
643 /// ```
644 pub fn insert_extension<T: Send + Sync + Clone + 'static>(
645 &mut self,
646 extension: T,
647 ) -> Option<T> {
648 self.extensions_mut().insert(extension)
649 }
650
651 /// Takes the response body, leaving a frozen (unusable) body in its place.
652 ///
653 /// This method extracts the body from the response while ensuring it cannot
654 /// be accessed again. This is useful when you need to consume the body
655 /// for processing while preventing accidental double-consumption.
656 ///
657 /// # Errors
658 ///
659 /// Returns `BodyFrozen` if the body has already been taken.
660 ///
661 /// # Examples
662 ///
663 /// ```rust
664 /// use http_kit::Response;
665 ///
666 /// let mut response = Response::new(200, "Hello, world!");
667 /// let body = response.take_body()?;
668 /// // response.take_body() would now return an error
669 /// # Ok::<(), http_kit::BodyError>(())
670 /// ```
671 pub fn take_body(&mut self) -> Result<Body, BodyFrozen> {
672 self.body.take()
673 }
674
675 /// Replaces the response body and returns the previous body.
676 ///
677 /// This method swaps the current body with a new one, returning the
678 /// original body. This is useful for body transformations or when
679 /// you need to temporarily substitute the body content.
680 ///
681 /// # Arguments
682 ///
683 /// * `body` - The new body to set (anything convertible to `Body`)
684 ///
685 /// # Examples
686 ///
687 /// ```rust
688 /// use http_kit::Response;
689 ///
690 /// let mut response = Response::new(200, "Original content");
691 /// let old_body = response.replace_body("New content");
692 /// // old_body contains "Original content"
693 /// // response now contains "New content"
694 /// ```
695 pub fn replace_body(&mut self, body: impl Into<Body>) -> Body {
696 self.body.replace(body.into())
697 }
698
699 /// Swaps the response body with another body.
700 ///
701 /// This method exchanges the contents of the response body with another body,
702 /// provided that the response body is not frozen.
703 ///
704 /// # Arguments
705 ///
706 /// * `body` - The body to swap with
707 ///
708 /// # Errors
709 ///
710 /// Returns `BodyFrozen` if the response body has been frozen/consumed.
711 ///
712 /// # Examples
713 ///
714 /// ```rust
715 /// use http_kit::{Response, Body};
716 ///
717 /// let mut response = Response::new(200, "Response content");
718 /// let mut other_body = Body::from_bytes("Other content");
719 /// response.swap_body(&mut other_body)?;
720 ///
721 /// // Now response contains "Other content"
722 /// // and other_body contains "Response content"
723 /// # Ok::<(), http_kit::BodyError>(())
724 /// ```
725 pub fn swap_body(&mut self, body: &mut Body) -> Result<(), BodyFrozen> {
726 self.body.swap(body)
727 }
728
729 /// Transforms the response body using the provided function.
730 ///
731 /// This method allows you to apply a transformation to the response body
732 /// in a functional style, returning a new response with the transformed body.
733 ///
734 /// # Arguments
735 ///
736 /// * `f` - A function that takes the current body and returns a new body
737 ///
738 /// # Examples
739 ///
740 /// ```rust
741 /// use http_kit::{Response, Body};
742 ///
743 /// let response = Response::new(200, "original")
744 /// .map_body(|body| {
745 /// // Transform body to uppercase JSON
746 /// Body::from_bytes(r#"{"message": "ORIGINAL"}"#)
747 /// });
748 /// ```
749 pub fn map_body<F>(mut self, f: F) -> Self
750 where
751 F: FnOnce(Body) -> Body,
752 {
753 self.body = f(self.body);
754 self
755 }
756
757 /// Sets the body from a JSON-serializable value.
758 ///
759 /// This method serializes the provided value to JSON and sets it as the response body.
760 /// It also automatically sets the `Content-Type` header to `application/json`.
761 ///
762 /// # Arguments
763 ///
764 /// * `value` - Any value that implements `serde::Serialize`
765 ///
766 /// # Errors
767 ///
768 /// Returns `serde_json::Error` if JSON serialization fails.
769 ///
770 /// # Examples
771 ///
772 /// ```rust
773 /// # #[cfg(feature = "json")]
774 /// # {
775 /// use http_kit::Response;
776 /// use serde::Serialize;
777 ///
778 /// #[derive(Serialize)]
779 /// struct ApiResponse { success: bool, message: String }
780 ///
781 /// let data = ApiResponse {
782 /// success: true,
783 /// message: "Operation completed".to_string(),
784 /// };
785 ///
786 /// let response = Response::empty().json(&data)?;
787 /// # }
788 /// # Ok::<(), serde_json::Error>(())
789 /// ```
790 #[cfg(feature = "json")]
791 pub fn json<T: serde::Serialize>(mut self, value: &T) -> Result<Self, serde_json::Error> {
792 use http::header;
793
794 self.insert_header(
795 header::CONTENT_TYPE,
796 HeaderValue::from_static("application/json"),
797 );
798 self.replace_body(Body::from_json(value)?);
799 Ok(self)
800 }
801
802 /// Sets the body from a file, streaming its contents.
803 ///
804 /// This method opens the specified file and streams its contents as the response body.
805 /// It automatically detects the MIME type based on the file extension and sets the
806 /// appropriate `Content-Type` header.
807 ///
808 /// # Arguments
809 ///
810 /// * `path` - Path to the file to read
811 ///
812 /// # Errors
813 ///
814 /// Returns `io::Error` if the file cannot be opened or read.
815 ///
816 /// # Examples
817 ///
818 /// ```rust,no_run
819 /// # #[cfg(feature = "fs")]
820 /// # {
821 /// use http_kit::Response;
822 ///
823 /// # async fn example() -> Result<(), std::io::Error> {
824 /// let response = Response::empty().file("static/logo.png").await?;
825 /// // Content-Type will be automatically set to "image/png"
826 /// # Ok(())
827 /// # }
828 /// # }
829 /// ```
830 #[cfg(feature = "fs")]
831 pub async fn file(
832 mut self,
833 path: impl AsRef<core::path::Path>,
834 ) -> Result<Self, core::io::Error> {
835 use core::os::unix::ffi::OsStrExt;
836
837 let path = path.as_ref();
838 let extension = path.extension().unwrap_or_default().as_bytes();
839 let mime = crate::mime_guess::guess(extension).unwrap_or("application/octet-stream");
840 self.replace_body(Body::from_file(path).await?);
841 self.insert_header(http::header::CONTENT_TYPE, HeaderValue::from_static(mime));
842 Ok(self)
843 }
844
845 /// Sets the body from a form-serializable value.
846 ///
847 /// This method serializes the provided value to URL-encoded form data and sets it
848 /// as the response body. It also automatically sets the `Content-Type` header to
849 /// `application/x-www-form-urlencoded`.
850 ///
851 /// # Arguments
852 ///
853 /// * `value` - Any value that implements `serde::Serialize`
854 ///
855 /// # Errors
856 ///
857 /// Returns `serde_urlencoded::ser::Error` if form serialization fails.
858 ///
859 /// # Examples
860 ///
861 /// ```rust
862 /// # #[cfg(feature = "form")]
863 /// # {
864 /// use http_kit::Response;
865 /// use serde::Serialize;
866 ///
867 /// #[derive(Serialize)]
868 /// struct FormData { key: String, value: String }
869 ///
870 /// let data = FormData {
871 /// key: "name".to_string(),
872 /// value: "Alice".to_string(),
873 /// };
874 ///
875 /// let response = Response::empty().form(&data)?;
876 /// # }
877 /// # Ok::<(), serde_urlencoded::ser::Error>(())
878 /// ```
879 #[cfg(feature = "form")]
880 pub fn form<T: serde::Serialize>(
881 mut self,
882 value: &T,
883 ) -> Result<Self, serde_urlencoded::ser::Error> {
884 use http::header;
885
886 self.insert_header(
887 header::CONTENT_TYPE,
888 HeaderValue::from_static("application/x-www-form-urlencoded"),
889 );
890 self.replace_body(Body::from_form(value)?);
891 Ok(self)
892 }
893
894 /// Consumes the response body and returns its data as bytes.
895 ///
896 /// This method takes the response body and reads all its data into memory,
897 /// returning it as a `Bytes` object. The body becomes unavailable after this call.
898 ///
899 /// # Errors
900 ///
901 /// Returns `BodyError` if:
902 /// - The body has already been consumed
903 /// - An I/O error occurs while reading streaming data
904 ///
905 /// # Examples
906 ///
907 /// ```rust
908 /// use http_kit::Response;
909 ///
910 /// # async fn example() -> Result<(), http_kit::BodyError> {
911 /// let mut response = Response::new(200, "Hello, world!");
912 /// let bytes = response.into_bytes().await?;
913 /// assert_eq!(bytes, "Hello, world!");
914 /// # Ok(())
915 /// # }
916 /// ```
917 pub async fn into_bytes(&mut self) -> Result<Bytes, BodyError> {
918 self.take_body()?.into_bytes().await
919 }
920
921 /// Consumes the response body and returns its data as a UTF-8 string.
922 ///
923 /// This method takes the response body, reads all its data into memory,
924 /// and converts it to a UTF-8 string. The body becomes unavailable after this call.
925 ///
926 /// # Errors
927 ///
928 /// Returns `BodyError` if:
929 /// - The body has already been consumed
930 /// - An I/O error occurs while reading streaming data
931 /// - The body contains invalid UTF-8 sequences
932 ///
933 /// # Examples
934 ///
935 /// ```rust
936 /// use http_kit::Response;
937 ///
938 /// # async fn example() -> Result<(), http_kit::BodyError> {
939 /// let mut response = Response::new(200, "Hello, world!");
940 /// let text = response.into_string().await?;
941 /// assert_eq!(text, "Hello, world!");
942 /// # Ok(())
943 /// # }
944 /// ```
945 pub async fn into_string(&mut self) -> Result<ByteStr, BodyError> {
946 self.take_body()?.into_string().await
947 }
948
949 /// Deserializes the response body as JSON into the specified type.
950 ///
951 /// This method reads the response body and attempts to deserialize it as JSON.
952 /// It validates that the `Content-Type` header is `application/json` before
953 /// attempting deserialization, making it safe for API clients.
954 ///
955 /// The deserialization is performed with zero-copy when possible by working
956 /// directly with the buffered byte data.
957 ///
958 /// # Errors
959 ///
960 /// Returns `crate::Error` if:
961 /// - The `Content-Type` header is not `application/json`
962 /// - The body has already been consumed
963 /// - The JSON is malformed or doesn't match the target type
964 ///
965 /// # Examples
966 ///
967 /// ```rust
968 /// # #[cfg(feature = "json")]
969 /// # {
970 /// use http_kit::Response;
971 /// use serde::Deserialize;
972 ///
973 /// #[derive(Deserialize)]
974 /// struct ApiResponse { success: bool, message: String }
975 ///
976 /// # async fn example() -> Result<(), http_kit::Error> {
977 /// let json_data = r#"{"success": true, "message": "OK"}"#;
978 /// let mut response = Response::new(200, json_data)
979 /// .header(http::header::CONTENT_TYPE, "application/json");
980 ///
981 /// let data: ApiResponse = response.into_json().await?;
982 /// assert!(data.success);
983 /// # Ok(())
984 /// # }
985 /// # }
986 /// ```
987 #[cfg(feature = "json")]
988 pub async fn into_json<'a, T>(&'a mut self) -> Result<T, crate::Error>
989 where
990 T: serde::Deserialize<'a>,
991 {
992 use crate::ResultExt;
993
994 assert_content_type!("application/json", self.headers());
995 serde_json::from_slice(self.body.as_bytes().await?).status(crate::StatusCode::BAD_REQUEST)
996 }
997
998 /// Deserializes the response body as URL-encoded form data into the specified type.
999 ///
1000 /// This method reads the response body and attempts to deserialize it as
1001 /// `application/x-www-form-urlencoded` data. It validates that the `Content-Type`
1002 /// header matches before attempting deserialization.
1003 ///
1004 /// The deserialization is performed with zero-copy when possible by working
1005 /// directly with the buffered byte data.
1006 ///
1007 /// # Errors
1008 ///
1009 /// Returns `crate::Error` if:
1010 /// - The `Content-Type` header is not `application/x-www-form-urlencoded`
1011 /// - The body has already been consumed
1012 /// - The form data is malformed or doesn't match the target type
1013 ///
1014 /// # Examples
1015 ///
1016 /// ```rust
1017 /// # #[cfg(feature = "form")]
1018 /// # {
1019 /// use http_kit::Response;
1020 /// use serde::Deserialize;
1021 ///
1022 /// #[derive(Deserialize)]
1023 /// struct FormResponse { status: String, code: u32 }
1024 ///
1025 /// # async fn example() -> Result<(), http_kit::Error> {
1026 /// let form_data = "status=success&code=200";
1027 /// let mut response = Response::new(200, form_data)
1028 /// .header(http::header::CONTENT_TYPE, "application/x-www-form-urlencoded");
1029 ///
1030 /// let data: FormResponse = response.into_form().await?;
1031 /// assert_eq!(data.status, "success");
1032 /// # Ok(())
1033 /// # }
1034 /// # }
1035 /// ```
1036 #[cfg(feature = "form")]
1037 pub async fn into_form<'a, T>(&'a mut self) -> Result<T, crate::Error>
1038 where
1039 T: serde::Deserialize<'a>,
1040 {
1041 use crate::ResultExt;
1042
1043 assert_content_type!("application/x-www-form-urlencoded", self.headers());
1044 serde_urlencoded::from_bytes(self.body.as_bytes().await?)
1045 .status(crate::StatusCode::BAD_REQUEST)
1046 }
1047
1048 /// Sets the MIME type for the response.
1049 ///
1050 /// This method sets the `Content-Type` header using a parsed MIME type,
1051 /// providing type safety and validation for content types.
1052 ///
1053 /// # Arguments
1054 ///
1055 /// * `mime` - The MIME type to set
1056 ///
1057 /// # Examples
1058 ///
1059 /// ```rust
1060 /// # #[cfg(feature = "mime")]
1061 /// # {
1062 /// use http_kit::Response;
1063 /// use mime;
1064 ///
1065 /// let response = Response::new(200, "Hello, world!")
1066 /// .mime(mime::TEXT_PLAIN);
1067 /// # }
1068 /// ```
1069 #[cfg(feature = "mime")]
1070 pub fn mime(mut self, mime: mime::Mime) -> Self {
1071 self.insert_header(
1072 http::header::CONTENT_TYPE,
1073 http::HeaderValue::from_str(mime.as_ref()).unwrap(),
1074 );
1075 self
1076 }
1077
1078 /// Parses the `Content-Type` header and returns a MIME type.
1079 ///
1080 /// This method attempts to parse the `Content-Type` header value as a MIME type,
1081 /// providing structured access to content type information.
1082 ///
1083 /// # Returns
1084 ///
1085 /// Returns `Some(mime::Mime)` if the header exists and can be parsed,
1086 /// or `None` if the header is missing or invalid.
1087 ///
1088 /// # Examples
1089 ///
1090 /// ```rust
1091 /// # #[cfg(feature = "mime")]
1092 /// # {
1093 /// use http_kit::Response;
1094 /// use mime;
1095 ///
1096 /// let response = Response::new(200, "Hello")
1097 /// .header(http::header::CONTENT_TYPE, "text/plain; charset=utf-8");
1098 ///
1099 /// if let Some(mime_type) = response.get_mime() {
1100 /// assert_eq!(mime_type.type_(), mime::TEXT);
1101 /// assert_eq!(mime_type.subtype(), mime::PLAIN);
1102 /// }
1103 /// # }
1104 /// ```
1105 #[cfg(feature = "mime")]
1106 pub fn get_mime(&self) -> Option<mime::Mime> {
1107 core::str::from_utf8(self.get_header(http::header::CONTENT_TYPE)?.as_bytes())
1108 .ok()?
1109 .parse()
1110 .ok()
1111 }
1112}