From 3203a3fd70bbb6883820437d89ad4a68616b2967 Mon Sep 17 00:00:00 2001 From: "D. Scott Boggs" Date: Thu, 8 Jun 2023 07:49:46 -0400 Subject: [PATCH] Add tracks routes --- Cargo.lock | 7 +++++ Cargo.toml | 10 ++++++ src/api/error.rs | 31 +++++++++++++++++++ src/api/mod.rs | 18 ++++++++--- src/api/tracks.rs | 69 ++++++++++++++++++++++++++++++++++++++++++ src/entities/tracks.rs | 3 +- src/main.rs | 2 +- 7 files changed, 133 insertions(+), 7 deletions(-) create mode 100644 src/api/error.rs create mode 100644 src/api/tracks.rs diff --git a/Cargo.lock b/Cargo.lock index 71fc438..22424ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -522,6 +522,9 @@ name = "either" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +dependencies = [ + "serde", +] [[package]] name = "encoding_rs" @@ -997,9 +1000,12 @@ name = "kalkulog-server" version = "0.1.0" dependencies = [ "derive_builder", + "either", "rocket", "sea-orm", "sea-orm-migration", + "serde", + "serde_json", "thiserror", "tokio", ] @@ -1603,6 +1609,7 @@ dependencies = [ "rocket_codegen", "rocket_http", "serde", + "serde_json", "state", "tempfile", "time", diff --git a/Cargo.toml b/Cargo.toml index 48680ea..7068bbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ path = "src/main.rs" [dependencies] sea-orm-migration = "0.11.3" +serde_json = "1.0.96" thiserror = "1.0.40" [dependencies.derive_builder] @@ -32,3 +33,12 @@ features = [ [dependencies.rocket] git = "https://github.com/SergioBenitez/Rocket" rev = "v0.5.0-rc.3" +features = ["json"] + +[dependencies.serde] +version = "1.0.163" +features = ["derive"] + +[dependencies.either] +version = "1.8.1" +features = ["serde"] diff --git a/src/api/error.rs b/src/api/error.rs new file mode 100644 index 0000000..602ca1d --- /dev/null +++ b/src/api/error.rs @@ -0,0 +1,31 @@ +use crate::error::Error; + +#[derive(Responder)] +#[response(status = 500, content_type = "json")] +pub(crate) struct ErrorResponder { + message: String, +} + +pub(crate) type ApiResult = Result; + +// The following impl's are for easy conversion of error types. + +impl From for ErrorResponder { + fn from(err: Error) -> ErrorResponder { + ErrorResponder { + message: err.to_string(), + } + } +} + +impl From for ErrorResponder { + fn from(string: String) -> ErrorResponder { + ErrorResponder { message: string } + } +} + +impl From<&str> for ErrorResponder { + fn from(str: &str) -> ErrorResponder { + str.to_owned().into() + } +} diff --git a/src/api/mod.rs b/src/api/mod.rs index 61cddfb..605c620 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,23 +1,31 @@ +mod error; +mod tracks; + use std::default::default; use std::net::{IpAddr, Ipv4Addr}; use rocket::Config; +use sea_orm::DatabaseConnection; -use crate::{ - entities::{prelude::*, *}, - rocket::{Build, Rocket}, -}; +use crate::rocket::{Build, Rocket}; + +pub(crate) use error::ErrorResponder; #[get("/status")] fn status() -> &'static str { "Ok" } -pub(crate) fn start_server() -> Rocket { +pub(crate) fn start_server(db: DatabaseConnection) -> Rocket { rocket::build() .configure(Config { address: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), ..default() }) + .manage(db) .mount("/", routes![status]) + .mount("/tracks", { + use tracks::*; + routes![all_tracks, track, insert_track, update_track, delete_track] + }) } diff --git a/src/api/tracks.rs b/src/api/tracks.rs new file mode 100644 index 0000000..a5983d2 --- /dev/null +++ b/src/api/tracks.rs @@ -0,0 +1,69 @@ +use crate::api::{self, error::ApiResult}; +use crate::entities::{prelude::*, *}; +use crate::error::Error; +use either::Either::{self, Left, Right}; +use rocket::http::Status; +use rocket::{serde::json::Json, State}; +use sea_orm::{prelude::*, DatabaseConnection}; + +#[get("/")] +pub(super) async fn all_tracks( + db: &State, +) -> ApiResult>> { + let db = db as &DatabaseConnection; + let tracks = Tracks::find().all(db).await.unwrap(); + Ok(Json(tracks)) +} + +#[get("/")] +pub(super) async fn track( + db: &State, + id: i32, +) -> Result, Either> { + let db = db as &DatabaseConnection; + match Tracks::find_by_id(id).one(db).await { + Ok(Some(track)) => Ok(Json(track)), + Ok(None) => Err(Left(Status::NotFound)), + Err(err) => Err(Right(Error::from(err).into())), + } +} + +#[post("/", format = "application/json", data = "")] +pub(super) async fn insert_track( + db: &State, + track: Json, +) -> ApiResult> { + let db = db as &DatabaseConnection; + Ok(Json( + tracks::ActiveModel::from_json(track.0) + .map_err(Error::from)? + .insert(db) + .await + .map_err(Error::from)?, + )) +} + +#[put("/", format = "application/json", data = "")] +pub(super) async fn update_track( + db: &State, + track: Json, +) -> ApiResult> { + let db = db as &DatabaseConnection; + Ok(Json( + tracks::ActiveModel::from_json(track.0) + .map_err(Error::from)? + .update(db) + .await + .map_err(Error::from)?, + )) +} + +#[delete("/")] +pub(super) async fn delete_track(db: &State, id: i32) -> ApiResult { + let db = db as &DatabaseConnection; + Tracks::delete_by_id(id) + .exec(db) + .await + .map_err(Error::from)?; + Ok(Status::Ok) +} diff --git a/src/entities/tracks.rs b/src/entities/tracks.rs index 57d360b..0791db6 100644 --- a/src/entities/tracks.rs +++ b/src/entities/tracks.rs @@ -1,8 +1,9 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3 use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] #[sea_orm(table_name = "tracks")] pub struct Model { #[sea_orm(primary_key)] diff --git a/src/main.rs b/src/main.rs index 20d5183..076f123 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,5 +32,5 @@ async fn rocket_defines_the_main_fn() -> _ { .has_table("track2_groups") .await .expect("fetch track2groups table")); - api::start_server() + api::start_server(db) }