feat: add model
This commit is contained in:
parent
c5f6a24b3a
commit
42a75ba800
6 changed files with 117 additions and 1 deletions
|
|
@ -6,8 +6,10 @@ pub type Result<T> = core::result::Result<T, Error>;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
LoginFail,
|
LoginFail,
|
||||||
|
PropertyDeleteFailIdNotFound { id: u64 },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// FIXME: return different status codes for different errors
|
||||||
impl IntoResponse for Error {
|
impl IntoResponse for Error {
|
||||||
fn into_response(self) -> Response {
|
fn into_response(self) -> Response {
|
||||||
println!("->> {:<12} - {self:?}", "INTO_RESPONSE");
|
println!("->> {:<12} - {self:?}", "INTO_RESPONSE");
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ use tower_cookies::CookieManagerLayer;
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
mod web;
|
mod web;
|
||||||
|
mod model;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct HelloParams {
|
struct HelloParams {
|
||||||
|
|
@ -29,7 +30,8 @@ async fn main() {
|
||||||
.merge(routes_hello())
|
.merge(routes_hello())
|
||||||
.merge(web::routes_login::routes())
|
.merge(web::routes_login::routes())
|
||||||
.layer(middleware::map_response(main_response_mapper))
|
.layer(middleware::map_response(main_response_mapper))
|
||||||
.layer(CookieManagerLayer::new())
|
.layer(CookieManagerLayer::new()) // must be above? the auth routes
|
||||||
|
// TODO: continue video at 22:15
|
||||||
.fallback_service(routes_static());
|
.fallback_service(routes_static());
|
||||||
|
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
|
|
@ -40,6 +42,10 @@ async fn main() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Map the response to add headers, etc.
|
||||||
|
///
|
||||||
|
/// * `res`: the response to map
|
||||||
async fn main_response_mapper(res: Response) -> Response {
|
async fn main_response_mapper(res: Response) -> Response {
|
||||||
println!("->> {:<12} - main_response_mapper", "HANDLER");
|
println!("->> {:<12} - main_response_mapper", "HANDLER");
|
||||||
|
|
||||||
|
|
@ -47,6 +53,7 @@ async fn main_response_mapper(res: Response) -> Response {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serve static files
|
||||||
fn routes_static() -> Router {
|
fn routes_static() -> Router {
|
||||||
Router::new().nest_service("/", get_service(ServeDir::new("./")))
|
Router::new().nest_service("/", get_service(ServeDir::new("./")))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
61
src/model.rs
Normal file
61
src/model.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
//! Simplistic model layer
|
||||||
|
//! (with mock-store layer)
|
||||||
|
|
||||||
|
use crate::{Error, Result};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
// region: --- Property Types
|
||||||
|
#[derive(Clone, Debug, Serialize)]
|
||||||
|
pub struct Property {
|
||||||
|
pub id: u64,
|
||||||
|
pub address: String,
|
||||||
|
pub contact: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct PropertyForCreate {
|
||||||
|
pub address: String,
|
||||||
|
pub contact: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion: --- Property Types
|
||||||
|
|
||||||
|
// region: --- Model Controller
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ModelController {
|
||||||
|
property_store: Arc<Mutex<Vec<Option<Property>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
impl ModelController {
|
||||||
|
pub async fn new() -> Result<Self> {
|
||||||
|
Ok(Self { property_store: Arc::default() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CRUD implementation
|
||||||
|
impl ModelController {
|
||||||
|
pub async fn create_property(&self, property: PropertyForCreate) -> Result<Property> {
|
||||||
|
let mut store = self.property_store.lock().unwrap();
|
||||||
|
let id = store.len() as u64;
|
||||||
|
let property = Property { id, address: property.address, contact: property.contact };
|
||||||
|
store.push(Some(property.clone()));
|
||||||
|
Ok(property)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn list_properties(&self) -> Result<Vec<Property>> {
|
||||||
|
let store = self.property_store.lock().unwrap();
|
||||||
|
let properties = store.iter().filter_map(|p| p.clone()).collect();
|
||||||
|
Ok(properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete_property(&self, id: u64) -> Result<Property> {
|
||||||
|
let mut store = self.property_store.lock().unwrap();
|
||||||
|
let property = store.get_mut(id as usize).and_then(|p| p.take());
|
||||||
|
property.ok_or(Error::PropertyDeleteFailIdNotFound { id })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion: --- Model Controller
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
pub mod routes_login;
|
pub mod routes_login;
|
||||||
|
pub mod routes_properties;
|
||||||
|
|
||||||
|
/// The cookie name for the auth token
|
||||||
pub const AUTH_TOKEN: &str = "auth-token";
|
pub const AUTH_TOKEN: &str = "auth-token";
|
||||||
|
|
|
||||||
34
src/web/routes_properties.rs
Normal file
34
src/web/routes_properties.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
use crate::model::{ModelController, Property, PropertyForCreate};
|
||||||
|
use crate::Result;
|
||||||
|
use axum::extract::{Path, State};
|
||||||
|
use axum::routing::{delete, post};
|
||||||
|
use axum::{Json, Router};
|
||||||
|
|
||||||
|
pub fn routes(mc: ModelController) -> Router {
|
||||||
|
Router::new()
|
||||||
|
.route("/properties", post(create_property).get(list_properties))
|
||||||
|
.route("/properties/:id", delete(delete_property))
|
||||||
|
.with_state(mc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// region: --- REST Handlers
|
||||||
|
|
||||||
|
async fn create_property(State(mc): State<ModelController>, Json(property_fc): Json<PropertyForCreate>) -> Result<Json<Property>> {
|
||||||
|
println!("->> {:<12} - create_property", "HANDLER");
|
||||||
|
let property = mc.create_property(property_fc).await?;
|
||||||
|
Ok(Json(property))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn list_properties(State(mc): State<ModelController>) -> Result<Json<Vec<Property>>> {
|
||||||
|
println!("->> {:<12} - list_properties", "HANDLER");
|
||||||
|
let properties = mc.list_properties().await?;
|
||||||
|
Ok(Json(properties))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn delete_property(State(mc): State<ModelController>, Path(id): Path<u64>) -> Result<Json<Property>> {
|
||||||
|
println!("->> {:<12} - delete_property", "HANDLER");
|
||||||
|
let property = mc.delete_property(id).await?;
|
||||||
|
Ok(Json(property))
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion: --- REST Handlers
|
||||||
|
|
@ -26,6 +26,16 @@ async fn test_quick_dev() -> Result<()> {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
req_login.await?.print().await?;
|
req_login.await?.print().await?;
|
||||||
|
let req_login = hc.do_post(
|
||||||
|
"/api/login",
|
||||||
|
json!(
|
||||||
|
{
|
||||||
|
"username": "demo1",
|
||||||
|
"password": "demowrong"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
req_login.await?.print().await?;
|
||||||
|
|
||||||
hc.do_get("/hello2/mike").await?.print().await?;
|
hc.do_get("/hello2/mike").await?.print().await?;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue