support static routes
This commit is contained in:
parent
167d34731c
commit
fe2311746b
@ -64,7 +64,6 @@ A test dataset of questions. Generated by [ChatGPT](https://chat.openai.com/)
|
||||
### Looking ahead
|
||||
These are a few things still to be added
|
||||
#### Higher priority
|
||||
* Support POST /answers
|
||||
* Add some simple API curl examples to this README
|
||||
* API documentation tooling (`utoipa`)
|
||||
* API testing tooling (`swagger`)
|
||||
@ -74,7 +73,6 @@ These are a few things still to be added
|
||||
* Optimize flush/file writing: Write out the JSON in a pretty structure and avoid re-writing the whole file in cases when it can be avoid (like adding 1 item)
|
||||
* Use a database alltogether instead of a json file for persistance
|
||||
* Serve basic web page(s) to utilize all APIs
|
||||
* Re-structure the application to serve API endpoint from an `api` directory, and generically serve web content from a `web` directory
|
||||
* Optimize the put/update handler to support path or body identification, and to update only individual fields passed.
|
||||
* Host application on my raspberry pi on the internet
|
||||
|
||||
|
@ -93,6 +93,7 @@ pub async fn delete_question(
|
||||
Err(e) => (StatusCode::NOT_FOUND, e).into_response(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an Answer
|
||||
/// # Parameters
|
||||
/// `answer_dto` Form URL encoded answer DTO
|
||||
@ -100,7 +101,6 @@ pub async fn delete_question(
|
||||
/// Status Created 201 and the created answer upon success
|
||||
/// Status Conflict 409 and message if answer with ID already exists
|
||||
/// Status Unprocessable Entity 422 is returned (implicitlly) for a malformed body
|
||||
|
||||
pub async fn create_answer(
|
||||
State(store): State<Arc<RwLock<Store>>>,
|
||||
Form(answer_dto): Form<AnswerDTO>,
|
||||
|
38
src/main.rs
38
src/main.rs
@ -4,7 +4,7 @@ mod question;
|
||||
mod store;
|
||||
use axum::{
|
||||
extract::{Path, Query, State},
|
||||
http::StatusCode,
|
||||
http::{StatusCode, Uri},
|
||||
response::{IntoResponse, Response},
|
||||
routing::{delete, get, post, put},
|
||||
Form, Json, Router,
|
||||
@ -13,22 +13,40 @@ use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs::File,
|
||||
io::{ErrorKind, Seek, Write},
|
||||
io::{ErrorKind, Read, Seek, Write},
|
||||
net::SocketAddr,
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
};
|
||||
use store::Store;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
async fn handle() -> Response {
|
||||
(StatusCode::OK, "Visiting the root").into_response()
|
||||
}
|
||||
|
||||
// generic handler for any not supported route/method combination
|
||||
async fn handler_404() -> Response {
|
||||
(StatusCode::NOT_FOUND, "404 Not Found").into_response()
|
||||
}
|
||||
|
||||
// generic handler to serve static for non-api routes
|
||||
async fn serve_file(uri: Uri) -> impl IntoResponse {
|
||||
let mut path_buf: PathBuf = PathBuf::from("./src/static/").join(uri.path().trim_start_matches('/'));
|
||||
if path_buf.is_dir() {
|
||||
path_buf.push("index.html")
|
||||
}
|
||||
match File::open(path_buf) {
|
||||
Ok(mut file) => {
|
||||
let mut contents = Vec::new();
|
||||
match file.read_to_end(&mut contents) {
|
||||
Ok(_) => axum::response::Response::builder()
|
||||
.status(StatusCode::OK)
|
||||
.body(axum::body::Body::from(contents))
|
||||
.unwrap(),
|
||||
Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Server Error").into_response(),
|
||||
}
|
||||
}
|
||||
Err(_) => (StatusCode::NOT_FOUND, "404 Not Found").into_response(),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let store: Arc<RwLock<Store>> = Arc::new(RwLock::new(store::Store::new()));
|
||||
@ -41,9 +59,11 @@ async fn main() {
|
||||
.route("/question", put(api::update_question))
|
||||
.route("/question/:id", delete(api::delete_question))
|
||||
.route("/answer", post(api::create_answer))
|
||||
.with_state(store)
|
||||
.with_state(store);
|
||||
let app = Router::new()
|
||||
.nest("/api/v1", apis)
|
||||
.route("/", get(serve_file))
|
||||
.route("/*path", get(serve_file))
|
||||
.fallback(handler_404);
|
||||
|
||||
let app = Router::new().route("/", get(handle)).merge(apis);
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
||||
|
8
src/static/cats/index.html
Normal file
8
src/static/cats/index.html
Normal file
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome again</title>
|
||||
</head>
|
||||
<body>
|
||||
Hello cats!
|
||||
</body>
|
||||
</html>
|
BIN
src/static/cats/warhol.jpg
Executable file
BIN
src/static/cats/warhol.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
8
src/static/index.html
Normal file
8
src/static/index.html
Normal file
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome</title>
|
||||
</head>
|
||||
<body>
|
||||
Hello world!
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user