first
This commit is contained in:
commit
fd8c97600a
8 changed files with 1712 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
/target
|
||||||
1560
Cargo.lock
generated
Normal file
1560
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
17
Cargo.toml
Normal file
17
Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
name = "learn_axum"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tokio = { version = "1.29.1", features = ["full"] }
|
||||||
|
axum = "0.6.18"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1"
|
||||||
|
tower-http = { version = "0.4.1", features = ["fs"] }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
anyhow = "1"
|
||||||
|
httpc-test = "0.1.1"
|
||||||
17
src/error.rs
Normal file
17
src/error.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
use axum::http::StatusCode;
|
||||||
|
use axum::response::{IntoResponse, Response};
|
||||||
|
|
||||||
|
pub type Result<T> = core::result::Result<T, Error>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
LoginFail,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoResponse for Error {
|
||||||
|
fn into_response(self) -> Response {
|
||||||
|
println!("->> {:<12} - {self:?}", "INTO_RESPONSE");
|
||||||
|
|
||||||
|
(StatusCode::INTERNAL_SERVER_ERROR, "UNHANDLED_CLIENT_ERROR").into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/main.rs
Normal file
60
src/main.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
pub use self::error::{Error, Result};
|
||||||
|
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
|
use axum::extract::{Path, Query};
|
||||||
|
use axum::http::{Method, Uri};
|
||||||
|
use axum::response::{Html, IntoResponse, Response};
|
||||||
|
use axum::routing::{get, get_service};
|
||||||
|
use axum::{middleware, Json, Router};
|
||||||
|
use axum::Server;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use tower_http::services::ServeDir;
|
||||||
|
|
||||||
|
|
||||||
|
mod error;
|
||||||
|
mod web;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct HelloParams {
|
||||||
|
name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let routes_all = Router::new()
|
||||||
|
.merge(routes_hello())
|
||||||
|
.merge(web::routes_login::routes())
|
||||||
|
.fallback_service(routes_static());
|
||||||
|
|
||||||
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
|
println!("->> Listening on {addr}\n");
|
||||||
|
Server::bind(&addr)
|
||||||
|
.serve(routes_all.into_make_service())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn routes_static() -> Router {
|
||||||
|
Router::new().nest_service("/", get_service(ServeDir::new("./")))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn routes_hello() -> Router {
|
||||||
|
Router::new().route("/hello", get(handler_hello))
|
||||||
|
.route("/hello2/:name", get(handler_hello2))
|
||||||
|
}
|
||||||
|
|
||||||
|
// e.g. `hello?name=jen`
|
||||||
|
async fn handler_hello(Query(params): Query<HelloParams>) -> impl IntoResponse {
|
||||||
|
println!("->> {:<12} - handler_hello - {params:?}", "HANDLER");
|
||||||
|
let name = params.name.as_deref().unwrap_or("World!");
|
||||||
|
Html(format!("Hello <strong>{name}</strong>!"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// e.g. `hello/jen`
|
||||||
|
async fn handler_hello2(Path(name): Path<String>) -> impl IntoResponse {
|
||||||
|
println!("->> {:<12} - handler_hello_path - {name:?}", "HANDLER");
|
||||||
|
Html(format!("Hello <strong>{name}</strong>!"))
|
||||||
|
}
|
||||||
1
src/web/mod.rs
Normal file
1
src/web/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod routes_login;
|
||||||
33
src/web/routes_login.rs
Normal file
33
src/web/routes_login.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
use crate::{Error, Result};
|
||||||
|
use axum::{Json, Router};
|
||||||
|
use axum::routing::post;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
|
pub fn routes() -> Router {
|
||||||
|
Router::new().route("/api/login", post(api_login))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn api_login(payload: Json<LoginPayload>) -> Result<Json<Value>>{
|
||||||
|
println!("->> {:<12} - api_login", "HANDLER");
|
||||||
|
|
||||||
|
if payload.username != "demo1" || payload.password != "demo1" {
|
||||||
|
return Err(Error::LoginFail);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Set cookies
|
||||||
|
|
||||||
|
let body = Json(json!({
|
||||||
|
"result": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
Ok(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct LoginPayload {
|
||||||
|
username: String,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
23
tests/quick_dev.rs
Normal file
23
tests/quick_dev.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_quick_dev() -> Result<()> {
|
||||||
|
let hc = httpc_test::new_client("http://localhost:3000")?;
|
||||||
|
hc.do_get("/hello?name=jen").await?.print().await?;
|
||||||
|
|
||||||
|
let hc = httpc_test::new_client("http://localhost:3000")?;
|
||||||
|
hc.do_get("/hello2/mike").await?.print().await?;
|
||||||
|
|
||||||
|
|
||||||
|
hc.do_get("/src/main.rs").await?.print().await?;
|
||||||
|
|
||||||
|
hc.do_get("/src/blub.rs").await?.print().await?;
|
||||||
|
|
||||||
|
let req_login = hc.do_post("/api/login", json!({"username": "demo1", "password": "demo1"}));
|
||||||
|
req_login.await?.print().await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue