chore: add pre-commit and format files
This commit is contained in:
parent
ed4322b8e9
commit
c558a6623c
9 changed files with 136 additions and 74 deletions
29
.pre-commit-config.yaml
Normal file
29
.pre-commit-config.yaml
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
default_install_hook_types: [commit-msg, pre-commit]
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v4.4.0
|
||||||
|
hooks:
|
||||||
|
- id: check-yaml
|
||||||
|
stages: [commit]
|
||||||
|
- id: check-json
|
||||||
|
stages: [commit]
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
stages: [commit]
|
||||||
|
- repo: https://github.com/commitizen-tools/commitizen
|
||||||
|
rev: 3.0.1
|
||||||
|
hooks:
|
||||||
|
- id: commitizen
|
||||||
|
stages:
|
||||||
|
- commit-msg
|
||||||
|
- repo: https://github.com/doublify/pre-commit-rust
|
||||||
|
rev: v1.0
|
||||||
|
hooks:
|
||||||
|
- id: fmt
|
||||||
|
- id: cargo-check
|
||||||
|
- id: clippy
|
||||||
|
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
|
||||||
|
rev: v9.5.0
|
||||||
|
hooks:
|
||||||
|
- id: commitlint
|
||||||
|
stages: [commit-msg]
|
||||||
|
additional_dependencies: ["@commitlint/config-conventional"]
|
||||||
1
commitlint.config.js
Normal file
1
commitlint.config.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
module.exports = {extends: ['@commitlint/config-conventional']}
|
||||||
13
src/log.rs
13
src/log.rs
|
|
@ -1,8 +1,8 @@
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use crate::{Error, Result};
|
|
||||||
use crate::ctx::Ctx;
|
use crate::ctx::Ctx;
|
||||||
use crate::error::ClientError;
|
use crate::error::ClientError;
|
||||||
|
use crate::{Error, Result};
|
||||||
use axum::http::{Method, Uri};
|
use axum::http::{Method, Uri};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
@ -16,11 +16,16 @@ pub async fn log_request(
|
||||||
ctx: Option<Ctx>,
|
ctx: Option<Ctx>,
|
||||||
service_error: Option<&Error>,
|
service_error: Option<&Error>,
|
||||||
client_error: Option<ClientError>,
|
client_error: Option<ClientError>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let timestamp = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_millis();
|
let timestamp = SystemTime::now()
|
||||||
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_millis();
|
||||||
|
|
||||||
let error_type = service_error.map(|se| se.as_ref().to_string());
|
let error_type = service_error.map(|se| se.as_ref().to_string());
|
||||||
let error_data = serde_json::to_value(service_error).ok().and_then(|mut v| v.get_mut("data").map(|v| v.take()));
|
let error_data = serde_json::to_value(service_error)
|
||||||
|
.ok()
|
||||||
|
.and_then(|mut v| v.get_mut("data").map(|v| v.take()));
|
||||||
|
|
||||||
// Create the RequestLogLine.
|
// Create the RequestLogLine.
|
||||||
let log_line = RequestLogLine {
|
let log_line = RequestLogLine {
|
||||||
|
|
|
||||||
29
src/main.rs
29
src/main.rs
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
use crate::model::ModelController;
|
use crate::model::ModelController;
|
||||||
|
|
||||||
pub use self::error::{Error, Result};
|
|
||||||
use self::ctx::Ctx;
|
use self::ctx::Ctx;
|
||||||
|
pub use self::error::{Error, Result};
|
||||||
use self::log::log_request;
|
use self::log::log_request;
|
||||||
|
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
@ -12,19 +12,19 @@ use axum::extract::{Path, Query};
|
||||||
use axum::http::{Method, Uri};
|
use axum::http::{Method, Uri};
|
||||||
use axum::response::{Html, IntoResponse, Response};
|
use axum::response::{Html, IntoResponse, Response};
|
||||||
use axum::routing::{get, get_service};
|
use axum::routing::{get, get_service};
|
||||||
use axum::{middleware, Json, Router};
|
|
||||||
use axum::Server;
|
use axum::Server;
|
||||||
|
use axum::{middleware, Json, Router};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tower_http::services::ServeDir;
|
|
||||||
use tower_cookies::CookieManagerLayer;
|
use tower_cookies::CookieManagerLayer;
|
||||||
|
use tower_http::services::ServeDir;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
mod ctx;
|
mod ctx;
|
||||||
mod error;
|
mod error;
|
||||||
mod log;
|
mod log;
|
||||||
mod web;
|
|
||||||
mod model;
|
mod model;
|
||||||
|
mod web;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct HelloParams {
|
struct HelloParams {
|
||||||
|
|
@ -32,17 +32,21 @@ struct HelloParams {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()>{
|
async fn main() -> Result<()> {
|
||||||
let mc = ModelController::new().await?;
|
let mc = ModelController::new().await?;
|
||||||
|
|
||||||
let routes_apis = web::routes_properties::routes(mc.clone()).route_layer(middleware::from_fn(web::mw_auth::mw_require_auth));
|
let routes_apis = web::routes_properties::routes(mc.clone())
|
||||||
|
.route_layer(middleware::from_fn(web::mw_auth::mw_require_auth));
|
||||||
|
|
||||||
let routes_all = Router::new()
|
let routes_all = Router::new()
|
||||||
.merge(routes_hello())
|
.merge(routes_hello())
|
||||||
.merge(web::routes_login::routes())
|
.merge(web::routes_login::routes())
|
||||||
.nest("/api", routes_apis)
|
.nest("/api", routes_apis)
|
||||||
.layer(middleware::map_response(main_response_mapper))
|
.layer(middleware::map_response(main_response_mapper))
|
||||||
.layer(middleware::from_fn_with_state(mc.clone(), web::mw_auth::mw_ctx_resolver))
|
.layer(middleware::from_fn_with_state(
|
||||||
|
mc.clone(),
|
||||||
|
web::mw_auth::mw_ctx_resolver,
|
||||||
|
))
|
||||||
.layer(CookieManagerLayer::new()) // must be above? the auth routes
|
.layer(CookieManagerLayer::new()) // must be above? the auth routes
|
||||||
.fallback_service(routes_static());
|
.fallback_service(routes_static());
|
||||||
|
|
||||||
|
|
@ -56,11 +60,15 @@ async fn main() -> Result<()>{
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Map the response to add headers, etc.
|
/// Map the response to add headers, etc.
|
||||||
///
|
///
|
||||||
/// * `res`: the response to map
|
/// * `res`: the response to map
|
||||||
async fn main_response_mapper(ctx: Option<Ctx>, uri: Uri, req_method: Method, res: Response) -> Response {
|
async fn main_response_mapper(
|
||||||
|
ctx: Option<Ctx>,
|
||||||
|
uri: Uri,
|
||||||
|
req_method: Method,
|
||||||
|
res: Response,
|
||||||
|
) -> Response {
|
||||||
println!("->> {:<12} - main_response_mapper", "RES_MAPPER");
|
println!("->> {:<12} - main_response_mapper", "RES_MAPPER");
|
||||||
let uuid = Uuid::new_v4();
|
let uuid = Uuid::new_v4();
|
||||||
|
|
||||||
|
|
@ -99,7 +107,8 @@ fn routes_static() -> Router {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn routes_hello() -> Router {
|
fn routes_hello() -> Router {
|
||||||
Router::new().route("/hello", get(handler_hello))
|
Router::new()
|
||||||
|
.route("/hello", get(handler_hello))
|
||||||
.route("/hello2/:name", get(handler_hello2))
|
.route("/hello2/:name", get(handler_hello2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
13
src/model.rs
13
src/model.rs
|
|
@ -1,7 +1,7 @@
|
||||||
//! Simplistic model layer
|
//! Simplistic model layer
|
||||||
//! (with mock-store layer)
|
//! (with mock-store layer)
|
||||||
|
|
||||||
use crate::{Error, Result, ctx::Ctx};
|
use crate::{ctx::Ctx, Error, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
|
@ -32,7 +32,9 @@ pub struct ModelController {
|
||||||
// Constructor
|
// Constructor
|
||||||
impl ModelController {
|
impl ModelController {
|
||||||
pub async fn new() -> Result<Self> {
|
pub async fn new() -> Result<Self> {
|
||||||
Ok(Self { property_store: Arc::default() })
|
Ok(Self {
|
||||||
|
property_store: Arc::default(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,7 +43,12 @@ impl ModelController {
|
||||||
pub async fn create_property(&self, ctx: Ctx, property: PropertyForCreate) -> Result<Property> {
|
pub async fn create_property(&self, ctx: Ctx, property: PropertyForCreate) -> Result<Property> {
|
||||||
let mut store = self.property_store.lock().unwrap();
|
let mut store = self.property_store.lock().unwrap();
|
||||||
let id = store.len() as u64;
|
let id = store.len() as u64;
|
||||||
let property = Property { id, creator_id: ctx.user_id(), address: property.address, contact: property.contact };
|
let property = Property {
|
||||||
|
id,
|
||||||
|
creator_id: ctx.user_id(),
|
||||||
|
address: property.address,
|
||||||
|
contact: property.contact,
|
||||||
|
};
|
||||||
store.push(Some(property.clone()));
|
store.push(Some(property.clone()));
|
||||||
Ok(property)
|
Ok(property)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use axum::RequestPartsExt;
|
|
||||||
use axum::extract::FromRequestParts;
|
use axum::extract::FromRequestParts;
|
||||||
use axum::http::Request;
|
|
||||||
use axum::http::request::Parts;
|
use axum::http::request::Parts;
|
||||||
|
use axum::http::Request;
|
||||||
use axum::middleware::Next;
|
use axum::middleware::Next;
|
||||||
use axum::response::Response;
|
use axum::response::Response;
|
||||||
|
use axum::RequestPartsExt;
|
||||||
use lazy_regex::regex_captures;
|
use lazy_regex::regex_captures;
|
||||||
use tower_cookies::{Cookies, Cookie};
|
use tower_cookies::{Cookie, Cookies};
|
||||||
|
|
||||||
use crate::ctx::Ctx;
|
use crate::ctx::Ctx;
|
||||||
use crate::web::AUTH_TOKEN;
|
use crate::web::AUTH_TOKEN;
|
||||||
|
|
@ -16,21 +16,22 @@ pub async fn mw_ctx_resolver<B>(
|
||||||
cookies: Cookies,
|
cookies: Cookies,
|
||||||
mut req: Request<B>,
|
mut req: Request<B>,
|
||||||
next: Next<B>,
|
next: Next<B>,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
println!("->> {:<12} - mw_ctx_resolver", "MIDDLEWARE");
|
println!("->> {:<12} - mw_ctx_resolver", "MIDDLEWARE");
|
||||||
|
|
||||||
let auth_token = cookies.get(AUTH_TOKEN).map(|c| c.value().to_string());
|
let auth_token = cookies.get(AUTH_TOKEN).map(|c| c.value().to_string());
|
||||||
|
|
||||||
// Compute Result<Ctx>.
|
// Compute Result<Ctx>.
|
||||||
let result_ctx = match auth_token.
|
let result_ctx = match auth_token
|
||||||
ok_or(Error::AuthFailNoAuthTokenCookie)
|
.ok_or(Error::AuthFailNoAuthTokenCookie)
|
||||||
.and_then(parse_token) {
|
.and_then(parse_token)
|
||||||
Ok((user_id, _exp, _sign)) => {
|
{
|
||||||
// TODO: Token components validations.
|
Ok((user_id, _exp, _sign)) => {
|
||||||
Ok(Ctx::new(user_id))
|
// TODO: Token components validations.
|
||||||
},
|
Ok(Ctx::new(user_id))
|
||||||
Err(e) => Err(e),
|
}
|
||||||
};
|
Err(e) => Err(e),
|
||||||
|
};
|
||||||
|
|
||||||
// Remove the cookie if something went wrong other than NoAuthTokenCookie.
|
// Remove the cookie if something went wrong other than NoAuthTokenCookie.
|
||||||
if result_ctx.is_err() && !matches!(result_ctx, Err(Error::AuthFailNoAuthTokenCookie)) {
|
if result_ctx.is_err() && !matches!(result_ctx, Err(Error::AuthFailNoAuthTokenCookie)) {
|
||||||
|
|
@ -47,7 +48,7 @@ pub async fn mw_ctx_resolver<B>(
|
||||||
pub async fn mw_require_auth<B>(
|
pub async fn mw_require_auth<B>(
|
||||||
ctx: Result<Ctx>,
|
ctx: Result<Ctx>,
|
||||||
req: Request<B>,
|
req: Request<B>,
|
||||||
next: Next<B>
|
next: Next<B>,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
println!("->> {:<12} - mw_require_auth - {ctx:?}", "MIDDLEWARE");
|
println!("->> {:<12} - mw_require_auth - {ctx:?}", "MIDDLEWARE");
|
||||||
|
|
||||||
|
|
@ -60,17 +61,17 @@ pub async fn mw_require_auth<B>(
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<S: Send + Sync> FromRequestParts<S> for Ctx {
|
impl<S: Send + Sync> FromRequestParts<S> for Ctx {
|
||||||
type Rejection = Error;
|
type Rejection = Error;
|
||||||
|
|
||||||
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self> {
|
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self> {
|
||||||
println!("->> {:<12} - Ctx", "EXTRACTOR");
|
println!("->> {:<12} - Ctx", "EXTRACTOR");
|
||||||
|
|
||||||
parts
|
parts
|
||||||
.extensions
|
.extensions
|
||||||
.get::<Result<Ctx>>()
|
.get::<Result<Ctx>>()
|
||||||
.ok_or(Error::AuthFailCtxNotInRequestExt)?
|
.ok_or(Error::AuthFailCtxNotInRequestExt)?
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion: --- Ctx Extractor
|
// endregion: --- Ctx Extractor
|
||||||
|
|
@ -80,7 +81,8 @@ impl<S: Send + Sync> FromRequestParts<S> for Ctx {
|
||||||
fn parse_token(token: String) -> Result<(u64, String, String)> {
|
fn parse_token(token: String) -> Result<(u64, String, String)> {
|
||||||
let (_whole, user_id, exp, sign) = regex_captures!(
|
let (_whole, user_id, exp, sign) = regex_captures!(
|
||||||
r#"^user-(\d+)\.(.+)\.(.+)"#, // a literal regex
|
r#"^user-(\d+)\.(.+)\.(.+)"#, // a literal regex
|
||||||
&token)
|
&token
|
||||||
|
)
|
||||||
.ok_or(Error::AuthFailTokenWrongFormat)?;
|
.ok_or(Error::AuthFailTokenWrongFormat)?;
|
||||||
|
|
||||||
let user_id: u64 = user_id
|
let user_id: u64 = user_id
|
||||||
|
|
@ -88,5 +90,4 @@ fn parse_token(token: String) -> Result<(u64, String, String)> {
|
||||||
.map_err(|_| Error::AuthFailTokenWrongFormat)?;
|
.map_err(|_| Error::AuthFailTokenWrongFormat)?;
|
||||||
|
|
||||||
Ok((user_id, exp.to_string(), sign.to_string()))
|
Ok((user_id, exp.to_string(), sign.to_string()))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{Error, Result, web};
|
use crate::{web, Error, Result};
|
||||||
use axum::{Json, Router};
|
|
||||||
use axum::routing::post;
|
use axum::routing::post;
|
||||||
|
use axum::{Json, Router};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use tower_cookies::{Cookie, Cookies};
|
use tower_cookies::{Cookie, Cookies};
|
||||||
|
|
@ -9,7 +9,7 @@ pub fn routes() -> Router {
|
||||||
Router::new().route("/api/login", post(api_login))
|
Router::new().route("/api/login", post(api_login))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn api_login(cookies: Cookies, payload: Json<LoginPayload>) -> Result<Json<Value>>{
|
async fn api_login(cookies: Cookies, payload: Json<LoginPayload>) -> Result<Json<Value>> {
|
||||||
println!("->> {:<12} - api_login", "HANDLER");
|
println!("->> {:<12} - api_login", "HANDLER");
|
||||||
|
|
||||||
if payload.username != "demo1" || payload.password != "demo1" {
|
if payload.username != "demo1" || payload.password != "demo1" {
|
||||||
|
|
@ -18,7 +18,7 @@ async fn api_login(cookies: Cookies, payload: Json<LoginPayload>) -> Result<Json
|
||||||
|
|
||||||
// FIXME: Implement real auth-token generation/signature.
|
// FIXME: Implement real auth-token generation/signature.
|
||||||
cookies.add(Cookie::new(web::AUTH_TOKEN, "user-1.exp.sign"));
|
cookies.add(Cookie::new(web::AUTH_TOKEN, "user-1.exp.sign"));
|
||||||
|
|
||||||
let body = Json(json!({
|
let body = Json(json!({
|
||||||
"result": {
|
"result": {
|
||||||
"success": true
|
"success": true
|
||||||
|
|
|
||||||
|
|
@ -14,19 +14,30 @@ pub fn routes(mc: ModelController) -> Router {
|
||||||
|
|
||||||
// region: --- REST Handlers
|
// region: --- REST Handlers
|
||||||
|
|
||||||
async fn create_property(State(mc): State<ModelController>, ctx: Ctx, Json(property_fc): Json<PropertyForCreate>) -> Result<Json<Property>> {
|
async fn create_property(
|
||||||
|
State(mc): State<ModelController>,
|
||||||
|
ctx: Ctx,
|
||||||
|
Json(property_fc): Json<PropertyForCreate>,
|
||||||
|
) -> Result<Json<Property>> {
|
||||||
println!("->> {:<12} - create_property", "HANDLER");
|
println!("->> {:<12} - create_property", "HANDLER");
|
||||||
let property = mc.create_property(ctx, property_fc).await?;
|
let property = mc.create_property(ctx, property_fc).await?;
|
||||||
Ok(Json(property))
|
Ok(Json(property))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn list_properties(State(mc): State<ModelController>, ctx: Ctx) -> Result<Json<Vec<Property>>> {
|
async fn list_properties(
|
||||||
|
State(mc): State<ModelController>,
|
||||||
|
ctx: Ctx,
|
||||||
|
) -> Result<Json<Vec<Property>>> {
|
||||||
println!("->> {:<12} - list_properties", "HANDLER");
|
println!("->> {:<12} - list_properties", "HANDLER");
|
||||||
let properties = mc.list_properties(ctx).await?;
|
let properties = mc.list_properties(ctx).await?;
|
||||||
Ok(Json(properties))
|
Ok(Json(properties))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete_property(State(mc): State<ModelController>, ctx: Ctx, Path(id): Path<u64>) -> Result<Json<Property>> {
|
async fn delete_property(
|
||||||
|
State(mc): State<ModelController>,
|
||||||
|
ctx: Ctx,
|
||||||
|
Path(id): Path<u64>,
|
||||||
|
) -> Result<Json<Property>> {
|
||||||
println!("->> {:<12} - delete_property", "HANDLER");
|
println!("->> {:<12} - delete_property", "HANDLER");
|
||||||
let property = mc.delete_property(ctx, id).await?;
|
let property = mc.delete_property(ctx, id).await?;
|
||||||
Ok(Json(property))
|
Ok(Json(property))
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ async fn test_quick_dev() -> Result<()> {
|
||||||
let hc = httpc_test::new_client("http://localhost:3000")?;
|
let hc = httpc_test::new_client("http://localhost:3000")?;
|
||||||
hc.do_get("/hello2/mike").await?.print().await?;
|
hc.do_get("/hello2/mike").await?.print().await?;
|
||||||
|
|
||||||
|
|
||||||
hc.do_get("/src/main.rs").await?.print().await?;
|
hc.do_get("/src/main.rs").await?.print().await?;
|
||||||
|
|
||||||
hc.do_get("/src/blub.rs").await?.print().await?;
|
hc.do_get("/src/blub.rs").await?.print().await?;
|
||||||
|
|
@ -19,22 +18,22 @@ async fn test_quick_dev() -> Result<()> {
|
||||||
let req_login = hc.do_post(
|
let req_login = hc.do_post(
|
||||||
"/api/login",
|
"/api/login",
|
||||||
json!(
|
json!(
|
||||||
{
|
{
|
||||||
"username": "demo1",
|
"username": "demo1",
|
||||||
"password": "demowrong"
|
"password": "demowrong"
|
||||||
}
|
}
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
req_login.await?.print().await?;
|
req_login.await?.print().await?;
|
||||||
let req_login = hc.do_post(
|
let req_login = hc.do_post(
|
||||||
"/api/login",
|
"/api/login",
|
||||||
json!(
|
json!(
|
||||||
{
|
{
|
||||||
"username": "demo1",
|
"username": "demo1",
|
||||||
"password": "demo1"
|
"password": "demo1"
|
||||||
}
|
}
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
req_login.await?.print().await?;
|
req_login.await?.print().await?;
|
||||||
|
|
||||||
hc.do_get("/hello2/mike").await?.print().await?;
|
hc.do_get("/hello2/mike").await?.print().await?;
|
||||||
|
|
@ -42,22 +41,22 @@ async fn test_quick_dev() -> Result<()> {
|
||||||
let req_create_property = hc.do_post(
|
let req_create_property = hc.do_post(
|
||||||
"/api/properties",
|
"/api/properties",
|
||||||
json!(
|
json!(
|
||||||
{
|
{
|
||||||
"address": "Lolilat Street 1",
|
"address": "Lolilat Street 1",
|
||||||
"contact": "01234 567890"
|
"contact": "01234 567890"
|
||||||
}
|
}
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
req_create_property.await?.print().await?;
|
req_create_property.await?.print().await?;
|
||||||
let req_create_property = hc.do_post(
|
let req_create_property = hc.do_post(
|
||||||
"/api/properties",
|
"/api/properties",
|
||||||
json!(
|
json!(
|
||||||
{
|
{
|
||||||
"address": "Lolilat Street 2",
|
"address": "Lolilat Street 2",
|
||||||
"contact": "01243 217890"
|
"contact": "01243 217890"
|
||||||
}
|
}
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
req_create_property.await?.print().await?;
|
req_create_property.await?.print().await?;
|
||||||
let req_get_properties = hc.do_get("/api/properties").await?;
|
let req_get_properties = hc.do_get("/api/properties").await?;
|
||||||
req_get_properties.print().await?;
|
req_get_properties.print().await?;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue