Basic error handling

This commit is contained in:
Knyffen 2024-08-13 21:50:17 +02:00
parent 565f1c497e
commit e05437b198
3 changed files with 68 additions and 9 deletions

View File

@ -2,7 +2,7 @@
use axum::{
extract::State,
http::header,
http::{header, StatusCode, Uri},
response::{Html, IntoResponse},
routing::get,
Router,
@ -15,7 +15,9 @@ use std::io::{BufWriter, Cursor};
use std::sync::Arc;
mod my_structs;
mod plotting;
use crate::my_structs::MyError;
use crate::plotting::Plotter;
use std::{thread, time};
#[derive(Clone)]
struct AppState {
@ -27,6 +29,9 @@ fn get_sql_pool(url: &str) -> Pool {
let sql_pool_attempt = Pool::new(url);
if let Ok(sql_pool) = sql_pool_attempt {
return sql_pool;
} else {
println!("Cannot connect to SQL database. Retrying");
thread::sleep(time::Duration::from_millis(1000));
}
}
}
@ -45,26 +50,53 @@ async fn main() {
.route("/image.png", get(png_image))
.route("/image.svg", get(svg_image))
.route("/image2.svg", get(svg_image2))
.with_state(shared_state);
.with_state(shared_state)
.fallback(not_found);
// run our app with hyper, listening globally on port 3000
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
async fn get_rows(State(state): State<Arc<AppState>>) -> String {
let mut conn = state.sql_pool.get_conn().unwrap();
async fn not_found(uri: Uri) -> (StatusCode, String) {
(StatusCode::NOT_FOUND, format!("No route for {uri}"))
}
async fn get_nutrition_rows(sql_pool: Pool) -> Result<Vec<my_structs::Nutrition>> {
let mut conn = sql_pool
.get_conn()
.expect("Cannot establish database connection");
let (nutrition_query, nutrition_closure) = my_structs::Nutrition::query_map_helper();
let nutrition_val: Vec<my_structs::Nutrition> =
conn.query_map(nutrition_query, nutrition_closure).unwrap();
let nutrition_val: Vec<my_structs::Nutrition> = conn
.query_map(nutrition_query, nutrition_closure)
.expect("Data in database doesn't match the Nutrition class");
Ok(nutrition_val)
}
async fn get_purchases_rows(sql_pool: Pool) -> Result<Vec<my_structs::Purchase>> {
let mut conn = sql_pool
.get_conn()
.expect("Cannot establish database connection");
let (purchases_query, purchases_closure) = my_structs::Purchase::query_map_helper();
let purchases_val: Vec<my_structs::Purchase> =
conn.query_map(purchases_query, purchases_closure).unwrap();
let purchases_val: Vec<my_structs::Purchase> = conn
.query_map(purchases_query, purchases_closure)
.expect("Data in database doesn't match the Purchase class");
Ok(purchases_val)
}
async fn get_rows(State(state): State<Arc<AppState>>) -> Result<String, MyError> {
let nutrition_val_promise = get_nutrition_rows(state.sql_pool.clone());
let purchases_val_promise = get_purchases_rows(state.sql_pool.clone());
let nutrition_val = nutrition_val_promise.await?;
let purchases_val = purchases_val_promise.await?;
println!("Serving: get_rows");
format!("{:#?} {:#?}", nutrition_val, purchases_val)
Ok(format!("{:#?} {:#?}", nutrition_val, purchases_val))
}
async fn html_demo(State(_state): State<Arc<AppState>>) -> Html<String> {

View File

@ -1,4 +1,6 @@
pub use self::myerror::MyError;
pub use self::nutrition::Nutrition;
pub use self::purchases::Purchase;
mod myerror;
mod nutrition;
mod purchases;

25
src/my_structs/myerror.rs Normal file
View File

@ -0,0 +1,25 @@
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
};
pub enum MyError {
MySQLError(mysql::Error),
}
impl IntoResponse for MyError {
fn into_response(self) -> Response {
let (status, message) = match self {
// # TODO: Don't expose error messages once this goes into production
MyError::MySQLError(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
};
(status, message).into_response()
}
}
impl From<mysql::Error> for MyError {
fn from(error: mysql::Error) -> Self {
Self::MySQLError(error)
}
}