main.rs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. use hyper::service::{make_service_fn, service_fn};
  2. use hyper::{Body, Method, Request, Response, StatusCode, Server};
  3. pub use mysql_async::prelude::*;
  4. pub use mysql_async::*;
  5. use std::convert::Infallible;
  6. use std::net::SocketAddr;
  7. use std::result::Result;
  8. use std::collections::HashMap;
  9. use serde::{Deserialize, Serialize};
  10. fn get_url() -> String {
  11. if let Ok(url) = std::env::var("DATABASE_URL") {
  12. let opts = Opts::from_url(&url).expect("DATABASE_URL invalid");
  13. if opts
  14. .db_name()
  15. .expect("a database name is required")
  16. .is_empty()
  17. {
  18. panic!("database name is empty");
  19. }
  20. url
  21. } else {
  22. "mysql://root:pass@127.0.0.1:3306/mysql".into()
  23. }
  24. }
  25. #[derive(Serialize, Deserialize, Debug)]
  26. struct Order {
  27. order_id: i32,
  28. product_id: i32,
  29. quantity: i32,
  30. amount: f32,
  31. shipping: f32,
  32. tax: f32,
  33. shipping_address: String,
  34. }
  35. impl Order {
  36. fn new(
  37. order_id: i32,
  38. product_id: i32,
  39. quantity: i32,
  40. amount: f32,
  41. shipping: f32,
  42. tax: f32,
  43. shipping_address: String,
  44. ) -> Self {
  45. Self {
  46. order_id,
  47. product_id,
  48. quantity,
  49. amount,
  50. shipping,
  51. tax,
  52. shipping_address,
  53. }
  54. }
  55. }
  56. async fn handle_request(req: Request<Body>, pool: Pool) -> Result<Response<Body>, anyhow::Error> {
  57. match (req.method(), req.uri().path()) {
  58. (&Method::GET, "/") => Ok(Response::new(Body::from(
  59. "The valid endpoints are /init /create_order /create_orders /update_order /orders /delete_order",
  60. ))),
  61. // Simply echo the body back to the client.
  62. (&Method::POST, "/echo") => Ok(Response::new(req.into_body())),
  63. // CORS OPTIONS
  64. (&Method::OPTIONS, "/init") => Ok(response_build(&String::from(""))),
  65. (&Method::OPTIONS, "/create_order") => Ok(response_build(&String::from(""))),
  66. (&Method::OPTIONS, "/create_orders") => Ok(response_build(&String::from(""))),
  67. (&Method::OPTIONS, "/update_order") => Ok(response_build(&String::from(""))),
  68. (&Method::OPTIONS, "/delete_order") => Ok(response_build(&String::from(""))),
  69. (&Method::OPTIONS, "/orders") => Ok(response_build(&String::from(""))),
  70. (&Method::GET, "/init") => {
  71. let mut conn = pool.get_conn().await.unwrap();
  72. "DROP TABLE IF EXISTS orders;".ignore(&mut conn).await?;
  73. "CREATE TABLE orders (order_id INT, product_id INT, quantity INT, amount FLOAT, shipping FLOAT, tax FLOAT, shipping_address VARCHAR(20));".ignore(&mut conn).await?;
  74. drop(conn);
  75. Ok(response_build("{\"status\":true}"))
  76. }
  77. (&Method::POST, "/create_order") => {
  78. let mut conn = pool.get_conn().await.unwrap();
  79. let byte_stream = hyper::body::to_bytes(req).await?;
  80. let order: Order = serde_json::from_slice(&byte_stream).unwrap();
  81. "INSERT INTO orders (order_id, product_id, quantity, amount, shipping, tax, shipping_address) VALUES (:order_id, :product_id, :quantity, :amount, :shipping, :tax, :shipping_address)"
  82. .with(params! {
  83. "order_id" => order.order_id,
  84. "product_id" => order.product_id,
  85. "quantity" => order.quantity,
  86. "amount" => order.amount,
  87. "shipping" => order.shipping,
  88. "tax" => order.tax,
  89. "shipping_address" => &order.shipping_address,
  90. })
  91. .ignore(&mut conn)
  92. .await?;
  93. drop(conn);
  94. Ok(response_build("{\"status\":true}"))
  95. }
  96. (&Method::POST, "/create_orders") => {
  97. let mut conn = pool.get_conn().await.unwrap();
  98. let byte_stream = hyper::body::to_bytes(req).await?;
  99. let orders: Vec<Order> = serde_json::from_slice(&byte_stream).unwrap();
  100. "INSERT INTO orders (order_id, product_id, quantity, amount, shipping, tax, shipping_address) VALUES (:order_id, :product_id, :quantity, :amount, :shipping, :tax, :shipping_address)"
  101. .with(orders.iter().map(|order| {
  102. params! {
  103. "order_id" => order.order_id,
  104. "product_id" => order.product_id,
  105. "quantity" => order.quantity,
  106. "amount" => order.amount,
  107. "shipping" => order.shipping,
  108. "tax" => order.tax,
  109. "shipping_address" => &order.shipping_address,
  110. }
  111. }))
  112. .batch(&mut conn)
  113. .await?;
  114. drop(conn);
  115. Ok(response_build("{\"status\":true}"))
  116. }
  117. (&Method::POST, "/update_order") => {
  118. let mut conn = pool.get_conn().await.unwrap();
  119. let byte_stream = hyper::body::to_bytes(req).await?;
  120. let order: Order = serde_json::from_slice(&byte_stream).unwrap();
  121. "UPDATE orders SET product_id=:product_id, quantity=:quantity, amount=:amount, shipping=:shipping, tax=:tax, shipping_address=:shipping_address WHERE order_id=:order_id"
  122. .with(params! {
  123. "product_id" => order.product_id,
  124. "quantity" => order.quantity,
  125. "amount" => order.amount,
  126. "shipping" => order.shipping,
  127. "tax" => order.tax,
  128. "shipping_address" => &order.shipping_address,
  129. "order_id" => order.order_id,
  130. })
  131. .ignore(&mut conn)
  132. .await?;
  133. drop(conn);
  134. Ok(response_build("{\"status\":true}"))
  135. }
  136. (&Method::GET, "/orders") => {
  137. let mut conn = pool.get_conn().await.unwrap();
  138. let orders = "SELECT * FROM orders"
  139. .with(())
  140. .map(&mut conn, |(order_id, product_id, quantity, amount, shipping, tax, shipping_address)| {
  141. Order::new(
  142. order_id,
  143. product_id,
  144. quantity,
  145. amount,
  146. shipping,
  147. tax,
  148. shipping_address,
  149. )},
  150. ).await?;
  151. drop(conn);
  152. Ok(response_build(serde_json::to_string(&orders)?.as_str()))
  153. }
  154. (&Method::GET, "/delete_order") => {
  155. let mut conn = pool.get_conn().await.unwrap();
  156. let params: HashMap<String, String> = req.uri().query().map(|v| {
  157. url::form_urlencoded::parse(v.as_bytes()).into_owned().collect()
  158. }).unwrap_or_else(HashMap::new);
  159. let order_id = params.get("id");
  160. "DELETE FROM orders WHERE order_id=:order_id"
  161. .with(params! { "order_id" => order_id, })
  162. .ignore(&mut conn)
  163. .await?;
  164. drop(conn);
  165. Ok(response_build("{\"status\":true}"))
  166. }
  167. // Return the 404 Not Found for other routes.
  168. _ => {
  169. let mut not_found = Response::default();
  170. *not_found.status_mut() = StatusCode::NOT_FOUND;
  171. Ok(not_found)
  172. }
  173. }
  174. }
  175. // CORS headers
  176. fn response_build(body: &str) -> Response<Body> {
  177. Response::builder()
  178. .header("Access-Control-Allow-Origin", "*")
  179. .header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
  180. .header("Access-Control-Allow-Headers", "api,Keep-Alive,User-Agent,Content-Type")
  181. .body(Body::from(body.to_owned()))
  182. .unwrap()
  183. }
  184. #[tokio::main(flavor = "current_thread")]
  185. async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
  186. let opts = Opts::from_url(&*get_url()).unwrap();
  187. let builder = OptsBuilder::from_opts(opts);
  188. // The connection pool will have a min of 5 and max of 10 connections.
  189. let constraints = PoolConstraints::new(5, 10).unwrap();
  190. let pool_opts = PoolOpts::default().with_constraints(constraints);
  191. let pool = Pool::new(builder.pool_opts(pool_opts));
  192. let addr = SocketAddr::from(([0, 0, 0, 0], 8080));
  193. let make_svc = make_service_fn(|_| {
  194. let pool = pool.clone();
  195. async move {
  196. Ok::<_, Infallible>(service_fn(move |req| {
  197. let pool = pool.clone();
  198. handle_request(req, pool)
  199. }))
  200. }
  201. });
  202. let server = Server::bind(&addr).serve(make_svc);
  203. if let Err(e) = server.await {
  204. eprintln!("server error: {}", e);
  205. }
  206. Ok(())
  207. }