Skip to content

Commit f99f581

Browse files
authored
Merge pull request #827 from http-rs/more-body-shorthands
Add body shorthands to `Response` and `ResponseBuilder`
2 parents d81eabc + 161bfec commit f99f581

File tree

2 files changed

+214
-0
lines changed

2 files changed

+214
-0
lines changed

src/response.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use std::convert::TryInto;
22
use std::fmt::{Debug, Display};
33
use std::ops::Index;
44

5+
use serde::Serialize;
6+
57
use crate::http::cookies::Cookie;
68
use crate::http::headers::{self, HeaderName, HeaderValues, ToHeaderValues};
79
use crate::http::{self, Body, Error, Mime, StatusCode};
@@ -229,6 +231,109 @@ impl Response {
229231
self.res.swap_body(body)
230232
}
231233

234+
/// Pass JSON as the response body.
235+
///
236+
/// # Mime
237+
///
238+
/// The `Content-Type` is set to `application/json`.
239+
///
240+
/// # Errors
241+
///
242+
/// This method will return an error if the provided data could not be serialized to JSON.
243+
///
244+
/// # Examples
245+
///
246+
/// ```no_run
247+
/// # use serde::{Deserialize, Serialize};
248+
/// # use tide::Response;
249+
/// # #[async_std::main]
250+
/// # async fn main() -> tide::Result<()> {
251+
/// #[derive(Deserialize, Serialize)]
252+
/// struct Ip {
253+
/// ip: String
254+
/// }
255+
///
256+
/// let data = &Ip { ip: "129.0.0.1".into() };
257+
/// let mut res = Response::new(200);
258+
/// res.body_json(data)?;
259+
/// # Ok(()) }
260+
/// ```
261+
pub fn body_json(&mut self, json: &impl Serialize) -> crate::Result<()> {
262+
self.res.set_body(Body::from_json(json)?);
263+
Ok(())
264+
}
265+
266+
/// Pass a string as the response body.
267+
///
268+
/// # Mime
269+
///
270+
/// The `Content-Type` is set to `text/plain; charset=utf-8`.
271+
///
272+
/// # Examples
273+
///
274+
/// ```no_run
275+
/// # use tide::Response;
276+
/// # #[async_std::main]
277+
/// # async fn main() -> tide::Result<()> {
278+
/// let data = "hello world".to_string();
279+
/// let mut res = Response::new(200);
280+
/// res.body_string(data);
281+
/// # Ok(()) }
282+
/// ```
283+
pub fn body_string(&mut self, string: String) {
284+
self.res.set_body(Body::from_string(string));
285+
}
286+
287+
/// Pass bytes as the request body.
288+
///
289+
/// # Mime
290+
///
291+
/// The `Content-Type` is set to `application/octet-stream`.
292+
///
293+
/// # Examples
294+
///
295+
/// ```no_run
296+
/// # use tide::Response;
297+
/// # #[async_std::main]
298+
/// # async fn main() -> tide::Result<()> {
299+
/// let data = b"hello world".to_owned();
300+
/// let mut res = Response::new(200);
301+
/// res.body_bytes(data);
302+
/// # Ok(()) }
303+
/// ```
304+
pub fn body_bytes(&mut self, bytes: impl AsRef<[u8]>) {
305+
self.set_body(Body::from(bytes.as_ref()));
306+
}
307+
308+
/// Pass a file as the response body.
309+
///
310+
/// # Mime
311+
///
312+
/// The `Content-Type` is set based on the file extension using [`mime_guess`] if the operation was
313+
/// successful. If `path` has no extension, or its extension has no known MIME type mapping,
314+
/// then `None` is returned.
315+
///
316+
/// [`mime_guess`]: https://docs.rs/mime_guess
317+
///
318+
/// # Errors
319+
///
320+
/// This method will return an error if the file couldn't be read.
321+
///
322+
/// # Examples
323+
///
324+
/// ```no_run
325+
/// # use tide::Response;
326+
/// # #[async_std::main]
327+
/// # async fn main() -> tide::Result<()> {
328+
/// let mut res = Response::new(200);
329+
/// res.body_file("./archive.tgz").await?;
330+
/// # Ok(()) }
331+
/// ```
332+
pub async fn body_file(&mut self, path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
333+
self.set_body(Body::from_file(path).await?);
334+
Ok(())
335+
}
336+
232337
/// Insert cookie in the cookie jar.
233338
pub fn insert_cookie(&mut self, cookie: Cookie<'static>) {
234339
self.cookie_events.push(CookieEvent::Added(cookie));

src/response_builder.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use serde::Serialize;
2+
13
use crate::http::headers::{HeaderName, ToHeaderValues};
24
use crate::http::{Body, Mime, StatusCode};
35
use crate::Response;
@@ -53,6 +55,9 @@ impl ResponseBuilder {
5355
}
5456

5557
/// Sets the Content-Type header on the response.
58+
///
59+
/// # Examples
60+
///
5661
/// ```
5762
/// # use tide::{http::mime, Response};
5863
/// let response = Response::builder(200).content_type(mime::HTML).build();
@@ -64,6 +69,9 @@ impl ResponseBuilder {
6469
}
6570

6671
/// Sets the body of the response.
72+
///
73+
/// # Examples
74+
///
6775
/// ```
6876
/// # async_std::task::block_on(async move {
6977
/// # use tide::{Response, convert::json};
@@ -75,6 +83,107 @@ impl ResponseBuilder {
7583
self.0.set_body(body);
7684
self
7785
}
86+
87+
/// Pass JSON as the response body.
88+
///
89+
/// # Mime
90+
///
91+
/// The `Content-Type` is set to `application/json`.
92+
///
93+
/// # Errors
94+
///
95+
/// This method will return an error if the provided data could not be serialized to JSON.
96+
///
97+
/// # Examples
98+
///
99+
/// ```no_run
100+
/// # use serde::{Deserialize, Serialize};
101+
/// # use tide::Response;
102+
/// # #[async_std::main]
103+
/// # async fn main() -> tide::Result<()> {
104+
/// #[derive(Deserialize, Serialize)]
105+
/// struct Ip {
106+
/// ip: String
107+
/// }
108+
///
109+
/// let data = &Ip { ip: "129.0.0.1".into() };
110+
/// let res = Response::builder(200).body_json(data)?.build();
111+
/// assert_eq!(res.status(), 200);
112+
/// # Ok(()) }
113+
/// ```
114+
pub fn body_json(self, json: &impl Serialize) -> crate::Result<Self> {
115+
Ok(self.body(Body::from_json(json)?))
116+
}
117+
118+
/// Pass a string as the response body.
119+
///
120+
/// # Mime
121+
///
122+
/// The `Content-Type` is set to `text/plain; charset=utf-8`.
123+
///
124+
/// # Examples
125+
///
126+
/// ```no_run
127+
/// # use tide::Response;
128+
/// # #[async_std::main]
129+
/// # async fn main() -> tide::Result<()> {
130+
/// let data = "hello world".to_string();
131+
/// let res = Response::builder(200).body_string(data).build();
132+
/// assert_eq!(res.status(), 200);
133+
/// # Ok(()) }
134+
/// ```
135+
pub fn body_string(self, string: String) -> Self {
136+
self.body(Body::from_string(string))
137+
}
138+
139+
/// Pass bytes as the response body.
140+
///
141+
/// # Mime
142+
///
143+
/// The `Content-Type` is set to `application/octet-stream`.
144+
///
145+
/// # Examples
146+
///
147+
/// ```no_run
148+
/// # use tide::Response;
149+
/// # #[async_std::main]
150+
/// # async fn main() -> tide::Result<()> {
151+
/// let data = b"hello world".to_owned();
152+
/// let res = Response::builder(200).body_bytes(data).build();
153+
/// assert_eq!(res.status(), 200);
154+
/// # Ok(()) }
155+
/// ```
156+
pub fn body_bytes(self, bytes: impl AsRef<[u8]>) -> Self {
157+
self.body(Body::from(bytes.as_ref()))
158+
}
159+
160+
/// Pass a file as the response body.
161+
///
162+
/// # Mime
163+
///
164+
/// The `Content-Type` is set based on the file extension using [`mime_guess`] if the operation was
165+
/// successful. If `path` has no extension, or its extension has no known MIME type mapping,
166+
/// then `None` is returned.
167+
///
168+
/// [`mime_guess`]: https://docs.rs/mime_guess
169+
///
170+
/// # Errors
171+
///
172+
/// This method will return an error if the file couldn't be read.
173+
///
174+
/// # Examples
175+
///
176+
/// ```no_run
177+
/// # use tide::Response;
178+
/// # #[async_std::main]
179+
/// # async fn main() -> tide::Result<()> {
180+
/// let res = Response::builder(200).body_file("./archive.tgz").await?.build();
181+
/// assert_eq!(res.status(), 200);
182+
/// # Ok(()) }
183+
/// ```
184+
pub async fn body_file(self, path: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
185+
Ok(self.body(Body::from_file(path).await?))
186+
}
78187
}
79188

80189
impl From<ResponseBuilder> for Response {

0 commit comments

Comments
 (0)