added axum store state to api routes

This commit is contained in:
David Westgate 2024-04-26 19:48:30 -07:00
parent fe94d752ef
commit 0c685d755c
4 changed files with 53 additions and 19 deletions

View File

@ -1,7 +1,11 @@
use axum::{ use axum::{
extract::{Path, State},
http::StatusCode, http::StatusCode,
response::{IntoResponse, Response}, response::{IntoResponse, Response},
Json,
}; };
use crate::question::{Question, Store};
/** /**
GET /questions (empty body; return JSON) GET /questions (empty body; return JSON)
POST /questions (JSON body; return HTTP status code) POST /questions (JSON body; return HTTP status code)
@ -10,24 +14,35 @@ DELETE /questions/:questionId (empty body; return HTTP status code)
POST /answers (www-url-encoded body; return HTTP status code) POST /answers (www-url-encoded body; return HTTP status code)
* *
*/ */
pub async fn get_questions() -> Response { pub async fn read_question(State(store): State<Store>, Path(id): Path<u8>) -> Response {
//TODO //TODO
(StatusCode::OK, " Get Questions").into_response() (StatusCode::OK, " Get Questions").into_response()
} }
pub async fn post_questions() -> Response { pub async fn read_all_questions(State(store): State<Store>) -> Response {
//TODO
(StatusCode::OK, " Get Questions").into_response()
}
pub async fn create_question(
State(store): State<Store>,
Json(question): Json<Question>,
) -> Response {
//TODO //TODO
(StatusCode::CREATED, "Post Questions").into_response() (StatusCode::CREATED, "Post Questions").into_response()
} }
pub async fn put_questions() -> Response { pub async fn update_question(
State(store): State<Store>,
Path(id): Path<u8>,
Json(question): Json<Question>,
) -> Response {
//TODO //TODO
(StatusCode::CREATED, "Put Questions..").into_response() (StatusCode::CREATED, "Put Questions..").into_response()
} }
pub async fn delete_questions() -> Response { pub async fn delete_question(State(store): State<Store>, Path(id): Path<u8>) -> Response {
//TODO //TODO
(StatusCode::OK, "Delete Questions..").into_response() (StatusCode::OK, "Delete Questions..").into_response()
} }
pub async fn post_answers() -> Response { pub async fn create_answer(State(store): State<Store> /*TODO */) -> Response {
//TODO //TODO
(StatusCode::CREATED, "Post Answers..").into_response() (StatusCode::CREATED, "Post Answers..").into_response()
} }

View File

@ -1,10 +1,14 @@
mod api; mod api;
mod err;
mod question;
use axum::{ use axum::{
http::StatusCode, http::StatusCode,
response::{IntoResponse, Response}, response::{IntoResponse, Response},
routing::{delete, get, post, put}, routing::{delete, get, post, put},
Router, Router,
}; };
use std::net::SocketAddr; use std::net::SocketAddr;
async fn handle() -> Response { async fn handle() -> Response {
@ -13,14 +17,19 @@ async fn handle() -> Response {
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
let store = question::Store::new();
let ip = SocketAddr::new([127, 0, 0, 1].into(), 3000); let ip = SocketAddr::new([127, 0, 0, 1].into(), 3000);
let listener = tokio::net::TcpListener::bind(ip).await.unwrap(); let listener = tokio::net::TcpListener::bind(ip).await.unwrap();
let apis = Router::new() let apis = Router::new()
.route("/questions", get(api::get_questions)) .route("/question/:id", get(api::read_question))
.route("/questions", post(api::post_questions)) .route("/questions", get(api::read_all_questions))
.route("/questions/:id", put(api::put_questions)) .route("/question", post(api::create_question))
.route("/questions", delete(api::delete_questions)) .route("/question/:id", put(api::update_question))
.route("/answers", post(api::post_answers)); .route("/question/:id", delete(api::delete_question))
.route("/answers", post(api::create_answer))
//.nest(path, router)
.with_state(store)
.fallback(err::handler_404);
let app = Router::new().route("/", get(handle)).merge(apis); let app = Router::new().route("/", get(handle)).merge(apis);
axum::serve(listener, app).await.unwrap(); axum::serve(listener, app).await.unwrap();

View File

@ -1,14 +1,19 @@
use std::collections::HashMap; use std::collections::HashMap;
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Clone)]
struct Store { pub(crate) struct Store {
questions: HashMap<u8, Question>, questions: HashMap<u8, Question>,
} }
impl Store { impl Store {
fn new() -> Self { pub fn new() -> Self {
Store { Store {
questions: Self::init(), questions: Self::init(),
} }
@ -18,7 +23,7 @@ impl Store {
serde_json::from_str(file).expect("can't read questions.json") serde_json::from_str(file).expect("can't read questions.json")
} }
fn add(mut self, question: Question) -> Result<Question, String> { pub fn add(mut self, question: Question) -> Result<Question, String> {
match self.questions.get(&question.id) { match self.questions.get(&question.id) {
Some(_) => Err(format!("Question with id {} already exists", question.id)), Some(_) => Err(format!("Question with id {} already exists", question.id)),
None => Ok(self None => Ok(self
@ -27,22 +32,22 @@ impl Store {
.unwrap()), .unwrap()),
} }
} }
fn remove(mut self, id: u8) -> Result<Question, String> { pub fn remove(mut self, id: u8) -> Result<Question, String> {
match self.questions.remove(&id) { match self.questions.remove(&id) {
Some(question) => Ok(question), Some(question) => Ok(question),
None => Err(format!("Question with id {} does not exist", id)), None => Err(format!("Question with id {} does not exist", id)),
} }
} }
fn fetch_one(self, id: u8) -> Result<Question, String> { pub fn fetch_one(self, id: u8) -> Result<Question, String> {
match self.questions.get(&id) { match self.questions.get(&id) {
Some(question) => Ok(question.clone()), Some(question) => Ok(question.clone()),
None => Err(format!("Question with id {} does not exist", id)), None => Err(format!("Question with id {} does not exist", id)),
} }
} }
fn fetch_all(self) -> Vec<Question> { pub fn fetch_all(self) -> Vec<Question> {
self.questions.values().cloned().collect() self.questions.values().cloned().collect()
} }
fn update(mut self, question: Question) -> Result<Question, String> { pub fn update(mut self, question: Question) -> Result<Question, String> {
match self.questions.get(&question.id) { match self.questions.get(&question.id) {
Some(_) => Ok(self Some(_) => Ok(self
.questions .questions
@ -70,3 +75,8 @@ impl Question {
} }
} }
} }
impl IntoResponse for &Question {
fn into_response(self) -> Response {
(StatusCode::OK, Json(&self)).into_response()
}
}

View File

@ -1,6 +1,6 @@
{ {
"1" : { "1" : {
"id": "1", "id": 1,
"title": "How?", "title": "How?",
"content": "Please help!", "content": "Please help!",
"tags": ["general"] "tags": ["general"]