Skip to content

Commit d35dbc1

Browse files
committed
refactor: add types to body parsing as well as add a lossy interpreter
2 parents b311fcc + 294c311 commit d35dbc1

File tree

5 files changed

+203
-171
lines changed

5 files changed

+203
-171
lines changed

examples/body_types.rs

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,37 @@ use tide::body;
66

77
#[derive(Serialize, Deserialize, Clone, Debug)]
88
struct Message {
9-
author: Option<String>,
10-
contents: String,
9+
author: Option<String>,
10+
contents: String,
1111
}
1212

13-
async fn echo_string(msg: String) -> String {
14-
println!("String: {}", msg);
15-
format!("{}", msg)
13+
async fn echo_string(msg: body::Str) -> String {
14+
println!("String: {}", msg.0);
15+
format!("{}", msg.0)
1616
}
1717

18-
async fn echo_vec(msg: Vec<u8>) -> String {
19-
println!("Vec<u8>: {:?}", msg);
18+
async fn echo_string_lossy(msg: body::StrLossy) -> String {
19+
println!("String: {}", msg.0);
20+
format!("{}", msg.0)
21+
}
22+
23+
async fn echo_vec(msg: body::Bytes) -> String {
24+
println!("Vec<u8>: {:?}", msg.0);
2025

21-
String::from_utf8(msg).unwrap()
26+
String::from_utf8(msg.0).unwrap()
2227
}
2328

2429
async fn echo_json(msg: body::Json<Message>) -> body::Json<Message> {
25-
println!("JSON: {:?}", msg.0);
30+
println!("JSON: {:?}", msg.0);
2631

27-
msg
32+
msg
2833
}
2934

3035
fn main() {
31-
let mut app = tide::App::new(());
32-
app.at("/echo/string").post(echo_string);
33-
app.at("/echo/vec").post(echo_vec);
34-
app.at("/echo/json").post(echo_json);
35-
app.serve("127.0.0.1:8000");
36+
let mut app = tide::App::new(());
37+
app.at("/echo/string").post(echo_string);
38+
app.at("/echo/string_lossy").post(echo_string_lossy);
39+
app.at("/echo/vec").post(echo_vec);
40+
app.at("/echo/json").post(echo_json);
41+
app.serve("127.0.0.1:8000");
3642
}

rustfmt.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
edition = "2018"

src/app.rs

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@ use futures::{
44
prelude::*,
55
};
66
use hyper::service::Service;
7-
use std::{sync::Arc, ops::{Deref, DerefMut}};
7+
use std::{
8+
ops::{Deref, DerefMut},
9+
sync::Arc,
10+
};
811

912
use crate::{
10-
router::{Resource, Router},
11-
Request,
12-
extract::Extract,
13-
RouteMatch,
14-
Response,
1513
body::Body,
16-
Middleware,
14+
extract::Extract,
15+
router::{Resource, Router},
16+
Middleware, Request, Response, RouteMatch,
1717
};
1818

1919
/// The top-level type for setting up a Tide application.
20-
///
20+
///
2121
/// Apps are equipped with a handle to their own state (`Data`), which is available to all endpoints.
2222
/// This is a "handle" because it must be `Clone`, and endpoints are invoked with a fresh clone.
2323
/// They also hold a top-level router.
@@ -57,21 +57,25 @@ impl<Data: Clone + Send + Sync + 'static> App<Data> {
5757
}
5858

5959
/// Start serving the app at the given address.
60-
///
60+
///
6161
/// Blocks the calling thread indefinitely.
6262
pub fn serve<A: std::net::ToSocketAddrs>(self, addr: A) {
6363
let server: Server<Data> = self.into_server();
6464

6565
// TODO: be more robust
6666
let addr = addr.to_socket_addrs().unwrap().next().unwrap();
6767

68-
let server = hyper::Server::bind(&addr).serve(move || {
69-
let res: Result<_, std::io::Error> = Ok(server.clone());
70-
res
71-
}).compat().map(|_| {
72-
let res: Result<(), ()> = Ok(());
73-
res
74-
}).compat();
68+
let server = hyper::Server::bind(&addr)
69+
.serve(move || {
70+
let res: Result<_, std::io::Error> = Ok(server.clone());
71+
res
72+
})
73+
.compat()
74+
.map(|_| {
75+
let res: Result<(), ()> = Ok(());
76+
res
77+
})
78+
.compat();
7579
hyper::rt::run(server);
7680
}
7781
}
@@ -94,35 +98,41 @@ impl<Data: Clone + Send + Sync + 'static> Service for Server<Data> {
9498
let router = self.router.clone();
9599
let middleware = self.middleware.clone();
96100

97-
let mut req = req.map(Body::from);
101+
let mut req = req.map(Body::from);
98102
let path = req.uri().path().to_owned();
99103
let method = req.method().to_owned();
100104

101-
FutureObj::new(Box::new(async move {
102-
if let Some((endpoint, params)) = router.route(&path, &method) {
103-
for m in middleware.iter() {
104-
match await!(m.request(&mut data, req, &params)) {
105-
Ok(new_req) => req = new_req,
106-
Err(resp) => return Ok(resp.map(Into::into)),
107-
}
105+
FutureObj::new(Box::new(
106+
async move {
107+
if let Some((endpoint, params)) = router.route(&path, &method) {
108+
for m in middleware.iter() {
109+
match await!(m.request(&mut data, req, &params)) {
110+
Ok(new_req) => req = new_req,
111+
Err(resp) => return Ok(resp.map(Into::into)),
112+
}
113+
}
114+
115+
let (head, mut resp) = await!(endpoint.call(data.clone(), req, params));
116+
117+
for m in middleware.iter() {
118+
resp = await!(m.response(&mut data, &head, resp))
119+
}
120+
121+
Ok(resp.map(Into::into))
122+
} else {
123+
Ok(http::Response::builder()
124+
.status(http::status::StatusCode::NOT_FOUND)
125+
.body(hyper::Body::empty())
126+
.unwrap())
108127
}
109-
110-
let (head, mut resp) = await!(endpoint.call(data.clone(), req, params));
111-
112-
for m in middleware.iter() {
113-
resp = await!(m.response(&mut data, &head, resp))
114-
}
115-
116-
Ok(resp.map(Into::into))
117-
} else {
118-
Ok(http::Response::builder().status(http::status::StatusCode::NOT_FOUND).body(hyper::Body::empty()).unwrap())
119-
}
120-
})).compat()
128+
},
129+
))
130+
.compat()
121131
}
122132
}
123133

124134
/// An extractor for accessing app data.
125-
///
135+
///
126136
/// Endpoints can use `AppData<T>` to gain a handle to the data (of type `T`) originally injected into their app.
127137
pub struct AppData<T>(pub T);
128138

@@ -140,11 +150,7 @@ impl<T> DerefMut for AppData<T> {
140150

141151
impl<T: Clone + Send + 'static> Extract<T> for AppData<T> {
142152
type Fut = future::Ready<Result<Self, Response>>;
143-
fn extract(
144-
data: &mut T,
145-
req: &mut Request,
146-
params: &RouteMatch<'_>,
147-
) -> Self::Fut {
153+
fn extract(data: &mut T, req: &mut Request, params: &RouteMatch<'_>) -> Self::Fut {
148154
future::ok(AppData(data.clone()))
149155
}
150-
}
156+
}

0 commit comments

Comments
 (0)