Skip to content

Commit a50128f

Browse files
committed
hyper: simplify handlers
- move the server header to the router and add it to all responses. - move the response boxing to the router simplifying the return types of each handler. hyperium/http-body#150 will simplify the router code even futher to the following: ```rust let mut response = match request.uri().path() { "/ping" => ping()?.box_body(), "/json" => json::get()?.box_body(), "/db" => single_query::get().await?.box_body(), "/queries" => multiple_queries::get(request.uri().query()).await?.box_body(), "/fortunes" => fortunes::get().await?.box_body(), "/plaintext" => plaintext::get()?.box_body(), _ => not_found_error()?.box_body(), }; ```
1 parent e871190 commit a50128f

File tree

6 files changed

+49
-68
lines changed

6 files changed

+49
-68
lines changed

frameworks/Rust/hyper/src/fortunes.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
use std::convert::Infallible;
21

3-
use http::header::{CONTENT_LENGTH, CONTENT_TYPE, SERVER};
2+
use http::header::{CONTENT_LENGTH, CONTENT_TYPE};
43
use http::Response;
5-
use http_body_util::combinators::BoxBody;
6-
use http_body_util::{BodyExt, Full};
4+
use http_body_util::Full;
75
use hyper::body::Bytes;
86
use tokio_postgres::Row;
97

108
use crate::db::POOL;
11-
use crate::{Error, SERVER_HEADER, TEXT_HTML};
9+
use crate::{Error, Result, TEXT_HTML};
1210

1311
const QUERY: &str = "SELECT id, message FROM fortune";
1412

@@ -26,18 +24,18 @@ impl From<&Row> for Fortune {
2624
}
2725
}
2826

29-
pub async fn get() -> crate::Result<Response<BoxBody<Bytes, Infallible>>> {
27+
pub async fn get() -> Result<Response<Full<Bytes>>> {
3028
let fortunes = tell_fortune().await?;
3129
let content = FortunesTemplate { fortunes }.to_string();
30+
3231
Response::builder()
33-
.header(SERVER, SERVER_HEADER.clone())
3432
.header(CONTENT_TYPE, TEXT_HTML.clone())
3533
.header(CONTENT_LENGTH, content.len())
36-
.body(Full::from(content).boxed())
34+
.body(content.into())
3735
.map_err(Error::from)
3836
}
3937

40-
async fn tell_fortune() -> crate::Result<Vec<Fortune>> {
38+
async fn tell_fortune() -> Result<Vec<Fortune>> {
4139
let db = POOL.get().await?;
4240
let statement = db.prepare_cached(QUERY).await?;
4341
let rows = db.query(&statement, &[]).await?;

frameworks/Rust/hyper/src/json.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
use std::convert::Infallible;
2-
3-
use http::header::{CONTENT_LENGTH, CONTENT_TYPE, SERVER};
1+
use http::header::{CONTENT_LENGTH, CONTENT_TYPE};
42
use http::Response;
5-
use http_body_util::combinators::BoxBody;
6-
use http_body_util::{BodyExt, Full};
3+
use http_body_util::Full;
74
use hyper::body::Bytes;
85
use serde::Serialize;
96

10-
use crate::{Error, Result, APPLICATION_JSON, SERVER_HEADER};
7+
use crate::{Error, Result, APPLICATION_JSON};
118

129
#[derive(Serialize)]
1310
struct JsonResponse<'a> {
@@ -18,12 +15,12 @@ static CONTENT: JsonResponse = JsonResponse {
1815
message: "Hello, world!",
1916
};
2017

21-
pub fn get() -> Result<Response<BoxBody<Bytes, Infallible>>> {
18+
pub fn get() -> Result<Response<Full<Bytes>>> {
2219
let content = serde_json::to_vec(&CONTENT)?;
20+
2321
Response::builder()
24-
.header(SERVER, SERVER_HEADER.clone())
2522
.header(CONTENT_TYPE, APPLICATION_JSON.clone())
2623
.header(CONTENT_LENGTH, content.len())
27-
.body(Full::from(content).boxed())
24+
.body(content.into())
2825
.map_err(Error::from)
2926
}

frameworks/Rust/hyper/src/main.rs

+16-17
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{io, thread};
44

55
use clap::{Parser, ValueEnum};
66
use http_body_util::combinators::BoxBody;
7-
use http_body_util::{BodyExt, Empty, Full};
7+
use http_body_util::Empty;
88
use hyper::body::{Bytes, Incoming};
99
use hyper::header::{HeaderValue, SERVER};
1010
use hyper::server::conn::http1;
@@ -181,32 +181,31 @@ async fn accept_loop(handle: runtime::Handle, listener: TcpListener) -> Result<(
181181
/// Routes requests to the appropriate handler.
182182
async fn router(request: Request<Incoming>) -> Result<Response<BoxBody<Bytes, Infallible>>> {
183183
// The method is always GET, so we don't check it.
184-
match request.uri().path() {
185-
"/ping" => ping(),
186-
"/json" => json::get(),
187-
"/db" => single_query::get().await,
188-
"/queries" => multiple_queries::get(request.uri().query()).await,
189-
"/fortunes" => fortunes::get().await,
190-
"/plaintext" => plaintext::get(),
191-
_ => not_found_error(),
192-
}
184+
let mut response = match request.uri().path() {
185+
"/ping" => ping()?.map(BoxBody::new),
186+
"/json" => json::get()?.map(BoxBody::new),
187+
"/db" => single_query::get().await?.map(BoxBody::new),
188+
"/queries" => multiple_queries::get(request.uri().query()).await?.map(BoxBody::new),
189+
"/fortunes" => fortunes::get().await?.map(BoxBody::new),
190+
"/plaintext" => plaintext::get()?.map(BoxBody::new),
191+
_ => not_found_error()?.map(BoxBody::new),
192+
};
193+
response.headers_mut().insert(SERVER, SERVER_HEADER.clone());
194+
Ok(response)
193195
}
194196

195197
/// A handler that returns a "pong" response.
196198
///
197199
/// This handler is used to verify that the server is running and can respond to requests. It is
198200
/// used by the docker health check command.
199-
fn ping() -> Result<Response<BoxBody<Bytes, Infallible>>> {
200-
Response::builder()
201-
.body(Full::from("pong").boxed())
202-
.map_err(Error::from)
201+
fn ping() -> Result<Response<String>> {
202+
Response::builder().body("pong".to_string()).map_err(Error::from)
203203
}
204204

205205
/// A handler that returns a 404 response.
206-
fn not_found_error() -> Result<Response<BoxBody<Bytes, Infallible>>> {
206+
fn not_found_error() -> Result<Response<Empty<Bytes>>> {
207207
Response::builder()
208208
.status(StatusCode::NOT_FOUND)
209-
.header(SERVER, SERVER_HEADER.clone())
210-
.body(Empty::new().boxed())
209+
.body(Empty::new())
211210
.map_err(Error::from)
212211
}

frameworks/Rust/hyper/src/multiple_queries.rs

+7-12
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
use std::convert::Infallible;
2-
3-
use http::header::{CONTENT_LENGTH, CONTENT_TYPE, SERVER};
1+
use http::header::{CONTENT_LENGTH, CONTENT_TYPE};
42
use http::Response;
5-
use http_body_util::combinators::BoxBody;
6-
use http_body_util::{BodyExt, Full};
3+
use http_body_util::Full;
74
use hyper::body::Bytes;
85
use serde::Serialize;
96
use tokio_postgres::Row;
107

118
use crate::db::POOL;
12-
use crate::{Error, Result, APPLICATION_JSON, SERVER_HEADER};
9+
use crate::{Error, Result, APPLICATION_JSON};
1310

1411
const QUERY: &str = "SELECT id, randomnumber FROM world WHERE id = $1";
1512

@@ -28,21 +25,19 @@ impl From<Row> for World {
2825
}
2926
}
3027

31-
pub async fn get(query: Option<&str>) -> Result<Response<BoxBody<Bytes, Infallible>>> {
28+
pub async fn get(query: Option<&str>) -> Result<Response<Full<Bytes>>> {
3229
let count = query
3330
.and_then(|query| query.strip_prefix("count="))
3431
.and_then(|query| query.parse().ok())
3532
.unwrap_or(1)
3633
.clamp(1, 500);
37-
3834
let worlds = query_worlds(count).await?;
39-
let json = serde_json::to_vec(&worlds)?;
35+
let content = serde_json::to_vec(&worlds)?;
4036

4137
Response::builder()
42-
.header(SERVER, SERVER_HEADER.clone())
4338
.header(CONTENT_TYPE, APPLICATION_JSON.clone())
44-
.header(CONTENT_LENGTH, json.len())
45-
.body(Full::from(json).boxed())
39+
.header(CONTENT_LENGTH, content.len())
40+
.body(content.into())
4641
.map_err(Error::from)
4742
}
4843

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
1-
use std::convert::Infallible;
2-
3-
use http::header::{CONTENT_LENGTH, CONTENT_TYPE, SERVER};
1+
use http::header::{CONTENT_LENGTH, CONTENT_TYPE};
42
use http::Response;
5-
use http_body_util::combinators::BoxBody;
6-
use http_body_util::{BodyExt, Full};
3+
use http_body_util::Full;
74
use hyper::body::Bytes;
85

9-
use crate::{Error, Result, SERVER_HEADER, TEXT_PLAIN};
6+
use crate::{Error, Result, TEXT_PLAIN};
107

118
static CONTENT: &[u8] = b"Hello, world!";
129

13-
pub fn get() -> Result<Response<BoxBody<Bytes, Infallible>>> {
10+
pub fn get() -> Result<Response<Full<Bytes>>> {
1411
Response::builder()
15-
.header(SERVER, SERVER_HEADER.clone())
1612
.header(CONTENT_TYPE, TEXT_PLAIN.clone())
1713
.header(CONTENT_LENGTH, CONTENT.len())
18-
.body(Full::from(CONTENT).boxed())
14+
.body(CONTENT.into())
1915
.map_err(Error::from)
2016
}

frameworks/Rust/hyper/src/single_query.rs

+8-12
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
use std::convert::Infallible;
2-
3-
use http::header::{CONTENT_LENGTH, CONTENT_TYPE, SERVER};
1+
use http::header::{CONTENT_LENGTH, CONTENT_TYPE};
42
use http::Response;
5-
use http_body_util::combinators::BoxBody;
6-
use http_body_util::{BodyExt, Full};
3+
use http_body_util::Full;
74
use hyper::body::Bytes;
85
use serde::Serialize;
96
use tokio_postgres::Row;
107

118
use crate::db::POOL;
12-
use crate::{Error, Result, APPLICATION_JSON, SERVER_HEADER};
9+
use crate::{Error, Result, APPLICATION_JSON};
1310

1411
static QUERY: &str = "SELECT id, randomnumber FROM world WHERE id = $1";
1512

@@ -28,16 +25,15 @@ impl From<Row> for World {
2825
}
2926
}
3027

31-
pub async fn get() -> Result<Response<BoxBody<Bytes, Infallible>>> {
28+
pub async fn get() -> Result<Response<Full<Bytes>>> {
3229
let id = fastrand::i32(1..10_000);
3330
let world = query_world(id).await?;
34-
let json = serde_json::to_vec(&world)?;
35-
31+
let content = serde_json::to_vec(&world)?;
32+
3633
Response::builder()
37-
.header(SERVER, SERVER_HEADER.clone())
3834
.header(CONTENT_TYPE, APPLICATION_JSON.clone())
39-
.header(CONTENT_LENGTH, json.len())
40-
.body(Full::from(json).boxed())
35+
.header(CONTENT_LENGTH, content.len())
36+
.body(content.into())
4137
.map_err(Error::from)
4238
}
4339

0 commit comments

Comments
 (0)