Browse Source

Axum fixes and updates (#7278)

* Remove unnecessary dependencies

* Edition 2021

* Remove extern crate

* Remove unnecessary allocation

* Update doc links

* Simplify parse_params

* Bump rust docker image

* Update axum
Artem Vorotnikov 3 years ago
parent
commit
3f80cbc3df

File diff suppressed because it is too large
+ 122 - 550
frameworks/Rust/axum/Cargo.lock


+ 13 - 11
frameworks/Rust/axum/Cargo.toml

@@ -2,7 +2,7 @@
 name = "axum"
 name = "axum"
 version = "0.1.2"
 version = "0.1.2"
 authors = ["Dragos Varovici <[email protected]>"]
 authors = ["Dragos Varovici <[email protected]>"]
-edition = "2018"
+edition = "2021"
 
 
 [[bin]]
 [[bin]]
 name = "axum"
 name = "axum"
@@ -21,26 +21,28 @@ name = "axum-mongo"
 path = "src/main_mongo.rs"
 path = "src/main_mongo.rs"
 
 
 [dependencies]
 [dependencies]
-num_cpus = { version = "^1.13" }
-rand = { version = "^0.8", features = ["small_rng"]}
+rand = { version = "^0.8", features = ["small_rng"] }
 yarte = { version = "^0.15" }
 yarte = { version = "^0.15" }
-async-stream = { version = "^0.3" }
 async-trait = { version = "0.1" }
 async-trait = { version = "0.1" }
-async-std = "1.10"
 futures = { version = "^0.3" }
 futures = { version = "^0.3" }
 futures-util = { version = "^0.3" }
 futures-util = { version = "^0.3" }
 dotenv = { version = "^0.15" }
 dotenv = { version = "^0.15" }
+num = { version = "0.4", default-features = false }
 serde = { version = "^1", features = ["derive"] }
 serde = { version = "^1", features = ["derive"] }
 serde_json = { version = "^1" }
 serde_json = { version = "^1" }
 serde_derive = { version = "^1" }
 serde_derive = { version = "^1" }
-axum = { version = "^0.3" }
+axum = { version = "0.5" }
 tokio = { version = "1.0", features = ["full"] }
 tokio = { version = "1.0", features = ["full"] }
 hyper = "0.14"
 hyper = "0.14"
 tower = { version = "0.4", features = ["util"] }
 tower = { version = "0.4", features = ["util"] }
-tower-http = { version = "0.1", features = ["set-header"] }
-sqlx = { version = "^0.5", features = [ "postgres", "macros", "runtime-tokio-native-tls" ] }
-bb8 = "0.7"
-bb8-postgres = "0.7"
+tower-http = { version = "0.2", features = ["set-header"] }
+sqlx = { version = "^0.5", features = [
+    "postgres",
+    "macros",
+    "runtime-tokio-native-tls",
+] }
+bb8 = "0.8"
+bb8-postgres = "0.8"
 tokio-postgres = "0.7"
 tokio-postgres = "0.7"
 tokio-pg-mapper = "0.2"
 tokio-pg-mapper = "0.2"
 tokio-pg-mapper-derive = "0.2"
 tokio-pg-mapper-derive = "0.2"
@@ -48,4 +50,4 @@ mongodb = "2.0"
 
 
 [profile.release]
 [profile.release]
 lto = true
 lto = true
-codegen-units = 1
+codegen-units = 1

+ 2 - 2
frameworks/Rust/axum/README.md

@@ -5,8 +5,8 @@
 
 
 Axum is a web application framework that focuses on ergonomics and modularity.
 Axum is a web application framework that focuses on ergonomics and modularity.
 
 
-* [User Guide](https://docs.rs/axum/0.3.0/axum/)
-* [API Documentation](https://docs.rs/axum/0.3.0/axum/)
+* [User Guide](https://docs.rs/axum/0.3/axum/)
+* [API Documentation](https://docs.rs/axum/0.3/axum/)
 * Cargo package: [axum](https://crates.io/crates/axum)
 * Cargo package: [axum](https://crates.io/crates/axum)
 
 
 ## Database
 ## Database

+ 1 - 1
frameworks/Rust/axum/axum-bb8.dockerfile

@@ -1,4 +1,4 @@
-FROM rust:1.55-slim-buster
+FROM rust:1.59-slim-bullseye
 
 
 ENV AXUM_TECHEMPOWER_DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world
 ENV AXUM_TECHEMPOWER_DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world
 
 

+ 1 - 1
frameworks/Rust/axum/axum-mongo.dockerfile

@@ -1,4 +1,4 @@
-FROM rust:1.55-slim-buster
+FROM rust:1.59-slim-bullseye
 
 
 ENV AXUM_TECHEMPOWER_MONGODB_URL=mongodb://tfb-database:27017
 ENV AXUM_TECHEMPOWER_MONGODB_URL=mongodb://tfb-database:27017
 
 

+ 1 - 1
frameworks/Rust/axum/axum-sqlx.dockerfile

@@ -1,4 +1,4 @@
-FROM rust:1.55-slim-buster
+FROM rust:1.59-slim-bullseye
 
 
 ENV AXUM_TECHEMPOWER_DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world
 ENV AXUM_TECHEMPOWER_DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world
 
 

+ 1 - 1
frameworks/Rust/axum/axum.dockerfile

@@ -1,4 +1,4 @@
-FROM rust:1.55-slim-buster
+FROM rust:1.59-slim-bullseye
 
 
 RUN apt-get update && apt-get install -y --no-install-recommends \
 RUN apt-get update && apt-get install -y --no-install-recommends \
     pkg-config libssl-dev \
     pkg-config libssl-dev \

+ 2 - 0
frameworks/Rust/axum/src/database_bb8.rs

@@ -1,5 +1,7 @@
 use axum::extract::{Extension, FromRequest, RequestParts};
 use axum::extract::{Extension, FromRequest, RequestParts};
 use axum::http::StatusCode;
 use axum::http::StatusCode;
+
+use async_trait::async_trait;
 use bb8::{Pool, PooledConnection};
 use bb8::{Pool, PooledConnection};
 use bb8_postgres::PostgresConnectionManager;
 use bb8_postgres::PostgresConnectionManager;
 use bb8_postgres::tokio_postgres::NoTls;
 use bb8_postgres::tokio_postgres::NoTls;

+ 1 - 0
frameworks/Rust/axum/src/database_mongo.rs

@@ -1,6 +1,7 @@
 use axum::extract::{Extension, FromRequest, RequestParts};
 use axum::extract::{Extension, FromRequest, RequestParts};
 use axum::http::StatusCode;
 use axum::http::StatusCode;
 
 
+use async_trait::async_trait;
 use mongodb::{Client, Database};
 use mongodb::{Client, Database};
 use crate::utils::internal_error;
 use crate::utils::internal_error;
 
 

+ 1 - 0
frameworks/Rust/axum/src/database_sqlx.rs

@@ -1,6 +1,7 @@
 use axum::extract::{Extension, FromRequest, RequestParts};
 use axum::extract::{Extension, FromRequest, RequestParts};
 use axum::http::StatusCode;
 use axum::http::StatusCode;
 
 
+use async_trait::async_trait;
 use sqlx::{PgPool, Postgres};
 use sqlx::{PgPool, Postgres};
 use sqlx::pool::PoolConnection;
 use sqlx::pool::PoolConnection;
 use sqlx::postgres::PgPoolOptions;
 use sqlx::postgres::PgPoolOptions;

+ 11 - 15
frameworks/Rust/axum/src/main.rs

@@ -1,23 +1,16 @@
-extern crate serde_derive;
-extern crate dotenv;
-extern crate async_trait;
-extern crate tokio_pg_mapper_derive;
-extern crate tokio_pg_mapper;
-
+mod common;
 mod models_common;
 mod models_common;
 mod server;
 mod server;
-mod common;
 
 
-use models_common::{Message};
+use models_common::Message;
 
 
 use axum::http::StatusCode;
 use axum::http::StatusCode;
-use axum::Json;
-use dotenv::dotenv;
-use axum::{Router, routing::get};
 use axum::http::{header, HeaderValue};
 use axum::http::{header, HeaderValue};
 use axum::response::IntoResponse;
 use axum::response::IntoResponse;
+use axum::Json;
+use axum::{routing::get, Router};
+use dotenv::dotenv;
 use tower_http::set_header::SetResponseHeaderLayer;
 use tower_http::set_header::SetResponseHeaderLayer;
-use hyper::Body;
 
 
 pub async fn plaintext() -> &'static str {
 pub async fn plaintext() -> &'static str {
     "Hello, World!"
     "Hello, World!"
@@ -35,14 +28,17 @@ pub async fn json() -> impl IntoResponse {
 async fn main() {
 async fn main() {
     dotenv().ok();
     dotenv().ok();
 
 
-    let app =  Router::new()
+    let app = Router::new()
         .route("/plaintext", get(plaintext))
         .route("/plaintext", get(plaintext))
         .route("/json", get(json))
         .route("/json", get(json))
-        .layer(SetResponseHeaderLayer::<_, Body>::if_not_present(header::SERVER, HeaderValue::from_static("Axum")));
+        .layer(SetResponseHeaderLayer::if_not_present(
+            header::SERVER,
+            HeaderValue::from_static("Axum"),
+        ));
 
 
     server::builder()
     server::builder()
         .http1_pipeline_flush(true)
         .http1_pipeline_flush(true)
         .serve(app.into_make_service())
         .serve(app.into_make_service())
         .await
         .await
         .unwrap();
         .unwrap();
-}
+}

+ 48 - 36
frameworks/Rust/axum/src/main_bb8.rs

@@ -1,37 +1,28 @@
-extern crate serde_derive;
-extern crate dotenv;
-#[macro_use]
-extern crate async_trait;
-
-mod models_common;
-mod models_bb8;
+mod common;
 mod database_bb8;
 mod database_bb8;
-mod utils;
+mod models_bb8;
+mod models_common;
 mod server;
 mod server;
-mod common;
+mod utils;
 
 
-use dotenv::dotenv;
-use std::env;
-use crate::database_bb8::{Connection, create_bb8_pool, DatabaseConnection};
+use crate::database_bb8::{create_bb8_pool, Connection, DatabaseConnection};
+use axum::http::{header, HeaderValue};
 use axum::{
 use axum::{
-    extract::{Query},
-    http::StatusCode,
-    response::IntoResponse,
-    routing::get,
-    AddExtensionLayer, Json, Router,
+    extract::Query, http::StatusCode, response::IntoResponse, routing::get, Extension,
+    Json, Router,
 };
 };
-use axum::http::{header, HeaderValue};
 use bb8_postgres::tokio_postgres::{Row, Statement};
 use bb8_postgres::tokio_postgres::{Row, Statement};
-use tower_http::set_header::SetResponseHeaderLayer;
-use hyper::Body;
+use dotenv::dotenv;
 use rand::rngs::SmallRng;
 use rand::rngs::SmallRng;
-use rand::{SeedableRng};
+use rand::SeedableRng;
+use std::env;
 use tokio_pg_mapper::FromTokioPostgresRow;
 use tokio_pg_mapper::FromTokioPostgresRow;
+use tower_http::set_header::SetResponseHeaderLayer;
 use yarte::Template;
 use yarte::Template;
 
 
-use models_bb8::{World, Fortune};
-use utils::{Params, parse_params, random_number};
 use crate::utils::Utf8Html;
 use crate::utils::Utf8Html;
+use models_bb8::{Fortune, World};
+use utils::{parse_params, random_number, Params};
 
 
 async fn db(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse {
 async fn db(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse {
     let mut rng = SmallRng::from_entropy();
     let mut rng = SmallRng::from_entropy();
@@ -43,25 +34,33 @@ async fn db(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse {
     (StatusCode::OK, Json(world))
     (StatusCode::OK, Json(world))
 }
 }
 
 
-async fn fetch_world_by_id_using_statement(conn: &Connection, number: i32, select: &Statement) -> World {
+async fn fetch_world_by_id_using_statement(
+    conn: &Connection,
+    number: i32,
+    select: &Statement,
+) -> World {
     let row: Row = conn.query_one(select, &[&number]).await.unwrap();
     let row: Row = conn.query_one(select, &[&number]).await.unwrap();
 
 
     World::from_row(row).unwrap()
     World::from_row(row).unwrap()
 }
 }
 
 
-async fn queries(DatabaseConnection(conn): DatabaseConnection, Query(params): Query<Params>) -> impl IntoResponse {
+async fn queries(
+    DatabaseConnection(conn): DatabaseConnection,
+    Query(params): Query<Params>,
+) -> impl IntoResponse {
     let q = parse_params(params);
     let q = parse_params(params);
 
 
     let mut rng = SmallRng::from_entropy();
     let mut rng = SmallRng::from_entropy();
 
 
-    let mut results = Vec::with_capacity(q as usize);
+    let mut results = Vec::with_capacity(q);
 
 
     let select = prepare_fetch_world_by_id_statement(&conn).await;
     let select = prepare_fetch_world_by_id_statement(&conn).await;
 
 
     for _ in 0..q {
     for _ in 0..q {
         let query_id = random_number(&mut rng);
         let query_id = random_number(&mut rng);
 
 
-        let result :World = fetch_world_by_id_using_statement(&conn, query_id, &select).await;
+        let result: World =
+            fetch_world_by_id_using_statement(&conn, query_id, &select).await;
 
 
         results.push(result);
         results.push(result);
     }
     }
@@ -96,18 +95,22 @@ async fn fortunes(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResp
     )
     )
 }
 }
 
 
-async fn updates(DatabaseConnection(conn): DatabaseConnection, Query(params): Query<Params>) -> impl IntoResponse {
+async fn updates(
+    DatabaseConnection(conn): DatabaseConnection,
+    Query(params): Query<Params>,
+) -> impl IntoResponse {
     let q = parse_params(params);
     let q = parse_params(params);
 
 
     let mut rng = SmallRng::from_entropy();
     let mut rng = SmallRng::from_entropy();
 
 
-    let mut results = Vec::with_capacity(q as usize);
+    let mut results = Vec::with_capacity(q);
 
 
     let select = prepare_fetch_world_by_id_statement(&conn).await;
     let select = prepare_fetch_world_by_id_statement(&conn).await;
 
 
     for _ in 0..q {
     for _ in 0..q {
         let query_id = random_number(&mut rng);
         let query_id = random_number(&mut rng);
-        let mut result :World = fetch_world_by_id_using_statement(&conn, query_id, &select).await;
+        let mut result: World =
+            fetch_world_by_id_using_statement(&conn, query_id, &select).await;
 
 
         result.randomnumber = random_number(&mut rng);
         result.randomnumber = random_number(&mut rng);
         results.push(result);
         results.push(result);
@@ -116,7 +119,9 @@ async fn updates(DatabaseConnection(conn): DatabaseConnection, Query(params): Qu
     let update = prepare_update_world_by_id_statement(&conn).await;
     let update = prepare_update_world_by_id_statement(&conn).await;
 
 
     for w in &results {
     for w in &results {
-        conn.execute(&update, &[&w.randomnumber, &w.id]).await.unwrap();
+        conn.execute(&update, &[&w.randomnumber, &w.id])
+            .await
+            .unwrap();
     }
     }
 
 
     (StatusCode::OK, Json(results))
     (StatusCode::OK, Json(results))
@@ -127,18 +132,22 @@ async fn prepare_fetch_all_fortunes_statement(conn: &Connection) -> Statement {
 }
 }
 
 
 async fn prepare_fetch_world_by_id_statement(conn: &Connection) -> Statement {
 async fn prepare_fetch_world_by_id_statement(conn: &Connection) -> Statement {
-    conn.prepare("SELECT id, randomnumber FROM World WHERE id = $1").await.unwrap()
+    conn.prepare("SELECT id, randomnumber FROM World WHERE id = $1")
+        .await
+        .unwrap()
 }
 }
 
 
 async fn prepare_update_world_by_id_statement(conn: &Connection) -> Statement {
 async fn prepare_update_world_by_id_statement(conn: &Connection) -> Statement {
-    conn.prepare("UPDATE World SET randomnumber = $1 WHERE id = $2").await.unwrap()
+    conn.prepare("UPDATE World SET randomnumber = $1 WHERE id = $2")
+        .await
+        .unwrap()
 }
 }
 
 
 #[tokio::main]
 #[tokio::main]
 async fn main() {
 async fn main() {
     dotenv().ok();
     dotenv().ok();
 
 
-    let database_url = env::var("AXUM_TECHEMPOWER_DATABASE_URL").ok()
+    let database_url = env::var("AXUM_TECHEMPOWER_DATABASE_URL")
         .expect("AXUM_TECHEMPOWER_DATABASE_URL environment variable was not set");
         .expect("AXUM_TECHEMPOWER_DATABASE_URL environment variable was not set");
 
 
     // setup connection pool
     // setup connection pool
@@ -149,8 +158,11 @@ async fn main() {
         .route("/db", get(db))
         .route("/db", get(db))
         .route("/queries", get(queries))
         .route("/queries", get(queries))
         .route("/updates", get(updates))
         .route("/updates", get(updates))
-        .layer(AddExtensionLayer::new(pool))
-        .layer(SetResponseHeaderLayer::<_, Body>::if_not_present(header::SERVER, HeaderValue::from_static("Axum")));
+        .layer(Extension(pool))
+        .layer(SetResponseHeaderLayer::if_not_present(
+            header::SERVER,
+            HeaderValue::from_static("Axum"),
+        ));
 
 
     server::builder()
     server::builder()
         .serve(router.into_make_service())
         .serve(router.into_make_service())

+ 45 - 35
frameworks/Rust/axum/src/main_mongo.rs

@@ -1,39 +1,30 @@
-extern crate serde_derive;
-extern crate dotenv;
-#[macro_use]
-extern crate async_trait;
-
+mod common;
+mod database_mongo;
 mod models_common;
 mod models_common;
 mod models_mongo;
 mod models_mongo;
-mod database_mongo;
-mod utils;
 mod server;
 mod server;
-mod common;
+mod utils;
 
 
-use dotenv::dotenv;
-use std::env;
-use std::time::Duration;
+use axum::http::{header, HeaderValue};
 use axum::{
 use axum::{
-    extract::{Query},
-    http::StatusCode,
-    response::IntoResponse,
-    routing::get,
-    AddExtensionLayer, Json, Router,
+    extract::Query, http::StatusCode, response::IntoResponse, routing::get, Extension,
+    Json, Router,
 };
 };
-use axum::http::{header, HeaderValue};
+use dotenv::dotenv;
 use futures::stream::StreamExt;
 use futures::stream::StreamExt;
-use tower_http::set_header::SetResponseHeaderLayer;
-use hyper::Body;
+use mongodb::options::ClientOptions;
+use mongodb::{bson::doc, Client, Database};
 use rand::rngs::SmallRng;
 use rand::rngs::SmallRng;
-use rand::{SeedableRng};
+use rand::SeedableRng;
+use std::env;
+use std::time::Duration;
+use tower_http::set_header::SetResponseHeaderLayer;
 use yarte::Template;
 use yarte::Template;
-use mongodb::{bson::doc, Client, Database};
-use mongodb::options::ClientOptions;
 
 
-use models_mongo::{World, Fortune};
-use utils::{Params, parse_params, random_number, Utf8Html};
 use database_mongo::DatabaseConnection;
 use database_mongo::DatabaseConnection;
 use models_mongo::FortuneInfo;
 use models_mongo::FortuneInfo;
+use models_mongo::{Fortune, World};
+use utils::{parse_params, random_number, Params, Utf8Html};
 
 
 async fn db(DatabaseConnection(mut db): DatabaseConnection) -> impl IntoResponse {
 async fn db(DatabaseConnection(mut db): DatabaseConnection) -> impl IntoResponse {
     let mut rng = SmallRng::from_entropy();
     let mut rng = SmallRng::from_entropy();
@@ -49,21 +40,28 @@ async fn find_world_by_id(db: &mut Database, number: i32) -> World {
 
 
     let filter = doc! { "id": number as f32 };
     let filter = doc! { "id": number as f32 };
 
 
-    let world: World = world_collection.find_one(Some(filter), None).await.expect("world could not be found").unwrap();
+    let world: World = world_collection
+        .find_one(Some(filter), None)
+        .await
+        .expect("world could not be found")
+        .unwrap();
     world
     world
 }
 }
 
 
-async fn queries(DatabaseConnection(mut db): DatabaseConnection, Query(params): Query<Params>) -> impl IntoResponse {
+async fn queries(
+    DatabaseConnection(mut db): DatabaseConnection,
+    Query(params): Query<Params>,
+) -> impl IntoResponse {
     let q = parse_params(params);
     let q = parse_params(params);
 
 
     let mut rng = SmallRng::from_entropy();
     let mut rng = SmallRng::from_entropy();
 
 
-    let mut results = Vec::with_capacity(q as usize);
+    let mut results = Vec::with_capacity(q);
 
 
     for _ in 0..q {
     for _ in 0..q {
         let query_id = random_number(&mut rng);
         let query_id = random_number(&mut rng);
 
 
-        let result :World =  find_world_by_id(&mut db, query_id).await;
+        let result: World = find_world_by_id(&mut db, query_id).await;
 
 
         results.push(result);
         results.push(result);
     }
     }
@@ -74,9 +72,12 @@ async fn queries(DatabaseConnection(mut db): DatabaseConnection, Query(params):
 async fn fortunes(DatabaseConnection(db): DatabaseConnection) -> impl IntoResponse {
 async fn fortunes(DatabaseConnection(db): DatabaseConnection) -> impl IntoResponse {
     let fortune_collection = db.collection::<Fortune>("fortune");
     let fortune_collection = db.collection::<Fortune>("fortune");
 
 
-    let mut fortune_cursor = fortune_collection.find(None, None).await.expect("fortunes could not be loaded");
+    let mut fortune_cursor = fortune_collection
+        .find(None, None)
+        .await
+        .expect("fortunes could not be loaded");
 
 
-    let mut fortunes: Vec<Fortune> = Vec::with_capacity(100 as usize);
+    let mut fortunes: Vec<Fortune> = Vec::with_capacity(100);
 
 
     while let Some(doc) = fortune_cursor.next().await {
     while let Some(doc) = fortune_cursor.next().await {
         fortunes.push(doc.expect("could not load fortune"));
         fortunes.push(doc.expect("could not load fortune"));
@@ -89,7 +90,13 @@ async fn fortunes(DatabaseConnection(db): DatabaseConnection) -> impl IntoRespon
 
 
     fortunes.sort_by(|a, b| a.message.cmp(&b.message));
     fortunes.sort_by(|a, b| a.message.cmp(&b.message));
 
 
-    let fortune_infos: Vec<FortuneInfo> = fortunes.iter().map(|f| FortuneInfo { id: f.id as i32, message: f.message.clone() }).collect();
+    let fortune_infos: Vec<FortuneInfo> = fortunes
+        .into_iter()
+        .map(|f| FortuneInfo {
+            id: f.id as i32,
+            message: f.message,
+        })
+        .collect();
 
 
     Utf8Html(
     Utf8Html(
         FortunesTemplate {
         FortunesTemplate {
@@ -104,7 +111,7 @@ async fn fortunes(DatabaseConnection(db): DatabaseConnection) -> impl IntoRespon
 async fn main() {
 async fn main() {
     dotenv().ok();
     dotenv().ok();
 
 
-    let database_url = env::var("AXUM_TECHEMPOWER_MONGODB_URL").ok()
+    let database_url = env::var("AXUM_TECHEMPOWER_MONGODB_URL")
         .expect("AXUM_TECHEMPOWER_MONGODB_URL environment variable was not set");
         .expect("AXUM_TECHEMPOWER_MONGODB_URL environment variable was not set");
 
 
     // setup connection pool
     // setup connection pool
@@ -119,8 +126,11 @@ async fn main() {
         .route("/fortunes", get(fortunes))
         .route("/fortunes", get(fortunes))
         .route("/db", get(db))
         .route("/db", get(db))
         .route("/queries", get(queries))
         .route("/queries", get(queries))
-        .layer(AddExtensionLayer::new(client))
-        .layer(SetResponseHeaderLayer::<_, Body>::if_not_present(header::SERVER, HeaderValue::from_static("Axum")));
+        .layer(Extension(client))
+        .layer(SetResponseHeaderLayer::if_not_present(
+            header::SERVER,
+            HeaderValue::from_static("Axum"),
+        ));
 
 
     server::builder()
     server::builder()
         .serve(app.into_make_service())
         .serve(app.into_make_service())
@@ -132,4 +142,4 @@ async fn main() {
 #[template(path = "fortunes.html.hbs")]
 #[template(path = "fortunes.html.hbs")]
 pub struct FortunesTemplate<'a> {
 pub struct FortunesTemplate<'a> {
     pub fortunes: &'a Vec<FortuneInfo>,
     pub fortunes: &'a Vec<FortuneInfo>,
-}
+}

+ 57 - 41
frameworks/Rust/axum/src/main_sqlx.rs

@@ -1,59 +1,60 @@
-extern crate serde_derive;
-extern crate dotenv;
-#[macro_use]
-extern crate async_trait;
-
+mod common;
+mod database_sqlx;
 mod models_common;
 mod models_common;
 mod models_sqlx;
 mod models_sqlx;
-mod database_sqlx;
-mod utils;
 mod server;
 mod server;
-mod common;
+mod utils;
 
 
-use dotenv::dotenv;
-use std::env;
-use crate::database_sqlx::{DatabaseConnection};
+use crate::database_sqlx::DatabaseConnection;
+use axum::http::{header, HeaderValue};
 use axum::{
 use axum::{
-    extract::{Query},
-    http::StatusCode,
-    response::IntoResponse,
-    routing::get,
-    AddExtensionLayer, Json, Router,
+    extract::Query, http::StatusCode, response::IntoResponse, routing::get, Extension,
+    Json, Router,
 };
 };
-use axum::http::{header, HeaderValue};
-use tower_http::set_header::SetResponseHeaderLayer;
-use hyper::Body;
+use dotenv::dotenv;
 use rand::rngs::SmallRng;
 use rand::rngs::SmallRng;
-use rand::{SeedableRng};
+use rand::SeedableRng;
 use sqlx::PgPool;
 use sqlx::PgPool;
+use std::env;
+use tower_http::set_header::SetResponseHeaderLayer;
 use yarte::Template;
 use yarte::Template;
 
 
-use models_sqlx::{World, Fortune};
 use database_sqlx::create_pool;
 use database_sqlx::create_pool;
-use utils::{Params, parse_params, random_number, Utf8Html};
+use models_sqlx::{Fortune, World};
+use utils::{parse_params, random_number, Params, Utf8Html};
 
 
 async fn db(DatabaseConnection(mut conn): DatabaseConnection) -> impl IntoResponse {
 async fn db(DatabaseConnection(mut conn): DatabaseConnection) -> impl IntoResponse {
     let mut rng = SmallRng::from_entropy();
     let mut rng = SmallRng::from_entropy();
     let number = random_number(&mut rng);
     let number = random_number(&mut rng);
 
 
-    let world : World = sqlx::query_as("SELECT id, randomnumber FROM World WHERE id = $1").bind(number)
-        .fetch_one(&mut conn).await.ok().expect("error loading world");
+    let world: World =
+        sqlx::query_as("SELECT id, randomnumber FROM World WHERE id = $1")
+            .bind(number)
+            .fetch_one(&mut conn)
+            .await
+            .expect("error loading world");
 
 
     (StatusCode::OK, Json(world))
     (StatusCode::OK, Json(world))
 }
 }
 
 
-async fn queries(DatabaseConnection(mut conn): DatabaseConnection, Query(params): Query<Params>) -> impl IntoResponse {
+async fn queries(
+    DatabaseConnection(mut conn): DatabaseConnection,
+    Query(params): Query<Params>,
+) -> impl IntoResponse {
     let q = parse_params(params);
     let q = parse_params(params);
 
 
     let mut rng = SmallRng::from_entropy();
     let mut rng = SmallRng::from_entropy();
 
 
-    let mut results = Vec::with_capacity(q as usize);
+    let mut results = Vec::with_capacity(q);
 
 
     for _ in 0..q {
     for _ in 0..q {
         let query_id = random_number(&mut rng);
         let query_id = random_number(&mut rng);
 
 
-        let result :World =  sqlx::query_as("SELECT * FROM World WHERE id = $1").bind(query_id)
-            .fetch_one(&mut conn).await.ok().expect("error loading world");
+        let result: World = sqlx::query_as("SELECT * FROM World WHERE id = $1")
+            .bind(query_id)
+            .fetch_one(&mut conn)
+            .await
+            .expect("error loading world");
 
 
         results.push(result);
         results.push(result);
     }
     }
@@ -61,9 +62,13 @@ async fn queries(DatabaseConnection(mut conn): DatabaseConnection, Query(params)
     (StatusCode::OK, Json(results))
     (StatusCode::OK, Json(results))
 }
 }
 
 
-async fn fortunes(DatabaseConnection(mut conn): DatabaseConnection) -> impl IntoResponse {
-    let mut fortunes: Vec<Fortune> = sqlx::query_as("SELECT * FROM Fortune").fetch_all(&mut conn).await
-        .ok().expect("Could not load Fortunes");
+async fn fortunes(
+    DatabaseConnection(mut conn): DatabaseConnection,
+) -> impl IntoResponse {
+    let mut fortunes: Vec<Fortune> = sqlx::query_as("SELECT * FROM Fortune")
+        .fetch_all(&mut conn)
+        .await
+        .expect("Could not load Fortunes");
 
 
     fortunes.push(Fortune {
     fortunes.push(Fortune {
         id: 0,
         id: 0,
@@ -81,17 +86,23 @@ async fn fortunes(DatabaseConnection(mut conn): DatabaseConnection) -> impl Into
     )
     )
 }
 }
 
 
-async fn updates(DatabaseConnection(mut conn): DatabaseConnection, Query(params): Query<Params>) -> impl IntoResponse {
+async fn updates(
+    DatabaseConnection(mut conn): DatabaseConnection,
+    Query(params): Query<Params>,
+) -> impl IntoResponse {
     let q = parse_params(params);
     let q = parse_params(params);
 
 
     let mut rng = SmallRng::from_entropy();
     let mut rng = SmallRng::from_entropy();
 
 
-    let mut results = Vec::with_capacity(q as usize);
+    let mut results = Vec::with_capacity(q);
 
 
     for _ in 0..q {
     for _ in 0..q {
         let query_id = random_number(&mut rng);
         let query_id = random_number(&mut rng);
-        let mut result :World =  sqlx::query_as("SELECT * FROM World WHERE id = $1").bind(query_id)
-            .fetch_one(&mut conn).await.ok().expect("error loading world");
+        let mut result: World = sqlx::query_as("SELECT * FROM World WHERE id = $1")
+            .bind(query_id)
+            .fetch_one(&mut conn)
+            .await
+            .expect("error loading world");
 
 
         result.random_number = random_number(&mut rng);
         result.random_number = random_number(&mut rng);
         results.push(result);
         results.push(result);
@@ -99,9 +110,11 @@ async fn updates(DatabaseConnection(mut conn): DatabaseConnection, Query(params)
 
 
     for w in &results {
     for w in &results {
         sqlx::query("UPDATE World SET randomnumber = $1 WHERE id = $2")
         sqlx::query("UPDATE World SET randomnumber = $1 WHERE id = $2")
-            .bind(w.random_number).bind(w.id)
+            .bind(w.random_number)
+            .bind(w.id)
             .execute(&mut conn)
             .execute(&mut conn)
-            .await.ok().expect("could not update world");
+            .await
+            .expect("could not update world");
     }
     }
 
 
     (StatusCode::OK, Json(results))
     (StatusCode::OK, Json(results))
@@ -111,7 +124,7 @@ async fn updates(DatabaseConnection(mut conn): DatabaseConnection, Query(params)
 async fn main() {
 async fn main() {
     dotenv().ok();
     dotenv().ok();
 
 
-    let database_url = env::var("AXUM_TECHEMPOWER_DATABASE_URL").ok()
+    let database_url = env::var("AXUM_TECHEMPOWER_DATABASE_URL")
         .expect("AXUM_TECHEMPOWER_DATABASE_URL environment variable was not set");
         .expect("AXUM_TECHEMPOWER_DATABASE_URL environment variable was not set");
 
 
     // setup connection pool
     // setup connection pool
@@ -131,12 +144,15 @@ async fn router(pool: PgPool) -> Router {
         .route("/db", get(db))
         .route("/db", get(db))
         .route("/queries", get(queries))
         .route("/queries", get(queries))
         .route("/updates", get(updates))
         .route("/updates", get(updates))
-        .layer(AddExtensionLayer::new(pool))
-        .layer(SetResponseHeaderLayer::<_, Body>::if_not_present(header::SERVER, HeaderValue::from_static("Axum")))
+        .layer(Extension(pool))
+        .layer(SetResponseHeaderLayer::if_not_present(
+            header::SERVER,
+            HeaderValue::from_static("Axum"),
+        ))
 }
 }
 
 
 #[derive(Template)]
 #[derive(Template)]
 #[template(path = "fortunes.html.hbs")]
 #[template(path = "fortunes.html.hbs")]
 pub struct FortunesTemplate<'a> {
 pub struct FortunesTemplate<'a> {
     pub fortunes: &'a Vec<Fortune>,
     pub fortunes: &'a Vec<Fortune>,
-}
+}

+ 26 - 39
frameworks/Rust/axum/src/utils.rs

@@ -1,10 +1,12 @@
-use std::convert::Infallible;
-use axum::body::{Bytes, Full};
-use axum::http::{header, HeaderValue, Response, StatusCode};
+use axum::http::{header, HeaderValue, StatusCode};
 use axum::response::IntoResponse;
 use axum::response::IntoResponse;
-use rand::Rng;
+use axum::{
+    body::{Bytes, Full},
+    response::Response,
+};
 use rand::rngs::SmallRng;
 use rand::rngs::SmallRng;
-use serde::{Deserialize};
+use rand::Rng;
+use serde::Deserialize;
 
 
 #[derive(Debug, Deserialize)]
 #[derive(Debug, Deserialize)]
 pub struct Params {
 pub struct Params {
@@ -15,36 +17,22 @@ pub fn random_number(rng: &mut SmallRng) -> i32 {
     (rng.gen::<u32>() % 10_000 + 1) as i32
     (rng.gen::<u32>() % 10_000 + 1) as i32
 }
 }
 
 
-pub fn parse_params(params: Params) -> i32 {
-    let mut q = 0;
-
-    if params.queries.is_some() {
-        let queries = params.queries.ok_or("could not get value").unwrap();
-
-        let queries_as_int = queries.parse::<i32>();
-
-        match queries_as_int {
-            Ok(_ok) => q = queries_as_int.unwrap(),
-            Err(_e) => q = 1,
-        }
-    }
-
-    let q = if q == 0 {
-        1
-    } else if q > 500 {
-        500
-    } else {
-        q
-    };
-
-    q
+pub fn parse_params(params: Params) -> usize {
+    num::clamp(
+        params
+            .queries
+            .map(|queries| queries.parse::<i32>().unwrap_or(1))
+            .unwrap_or(0),
+        1,
+        500,
+    ) as usize
 }
 }
 
 
 /// Utility function for mapping any error into a `500 Internal Server Error`
 /// Utility function for mapping any error into a `500 Internal Server Error`
 /// response.
 /// response.
 pub fn internal_error<E>(err: E) -> (StatusCode, String)
 pub fn internal_error<E>(err: E) -> (StatusCode, String)
-    where
-        E: std::error::Error,
+where
+    E: std::error::Error,
 {
 {
     (StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
     (StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
 }
 }
@@ -53,16 +41,15 @@ pub fn internal_error<E>(err: E) -> (StatusCode, String)
 pub struct Utf8Html<T>(pub T);
 pub struct Utf8Html<T>(pub T);
 
 
 impl<T> IntoResponse for Utf8Html<T>
 impl<T> IntoResponse for Utf8Html<T>
-    where
-        T: Into<Full<Bytes>>,
+where
+    T: Into<Full<Bytes>>,
 {
 {
-    type Body = Full<Bytes>;
-    type BodyError = Infallible;
-
-    fn into_response(self) -> Response<Self::Body> {
-        let mut res = Response::new(self.0.into());
-        res.headers_mut()
-            .insert(header::CONTENT_TYPE, HeaderValue::from_static("text/html; charset=utf-8"));
+    fn into_response(self) -> Response {
+        let mut res = self.0.into().into_response();
+        res.headers_mut().insert(
+            header::CONTENT_TYPE,
+            HeaderValue::from_static("text/html; charset=utf-8"),
+        );
         res
         res
     }
     }
 }
 }

Some files were not shown because too many files changed in this diff