webapi, inital schema and routes (get_users)
provides the infrastructure for the webapi including setting up the server and the routes. Implements get_users as a test route
This commit is contained in:
parent
1400b2fc95
commit
92763fd7dc
7 changed files with 197 additions and 0 deletions
25
koucha/src/bin/webapi/main.rs
Normal file
25
koucha/src/bin/webapi/main.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use koucha::{
|
||||
AdapterBuilder,
|
||||
Adapter,
|
||||
};
|
||||
|
||||
mod routes;
|
||||
mod types;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct AppState {
|
||||
pub adapter: Adapter,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let db_url = std::env::var("DATABASE_URL").unwrap();
|
||||
let adapter = AdapterBuilder::new()
|
||||
.database_url(&db_url)
|
||||
.create().await.unwrap();
|
||||
|
||||
let app = routes::router().with_state(AppState { adapter });
|
||||
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:4142").await.unwrap();
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
||||
36
koucha/src/bin/webapi/routes/get_users.rs
Normal file
36
koucha/src/bin/webapi/routes/get_users.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
use axum::{Json, extract::State};
|
||||
use koucha::db::User as DbUser;
|
||||
use reqwest::StatusCode;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use crate::{
|
||||
AppState, routes::{ApiError, ApiResult, ApiResponse}, types::User
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Input { }
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Output {
|
||||
users: Vec<User>,
|
||||
}
|
||||
|
||||
pub async fn handler(
|
||||
State(state): State<AppState>,
|
||||
Json(_body): Json<Input>,
|
||||
) -> ApiResult<Output> {
|
||||
let dbusers = DbUser::get_all(state.adapter.get_pool())
|
||||
.await.map_err(|_e| {
|
||||
// TODO: Logging
|
||||
ApiError {
|
||||
status: StatusCode::INTERNAL_SERVER_ERROR,
|
||||
error: "InternalError",
|
||||
message: "Error getting all users from DB.".to_string(),
|
||||
}
|
||||
})?;
|
||||
|
||||
let users: Vec<User> = dbusers.iter().map(|u| User {
|
||||
name: u.name().to_string(),
|
||||
}).collect();
|
||||
|
||||
Ok(ApiResponse(StatusCode::OK, Output { users }))
|
||||
}
|
||||
35
koucha/src/bin/webapi/routes/mod.rs
Normal file
35
koucha/src/bin/webapi/routes/mod.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
use serde::Serialize;
|
||||
use serde_json::json;
|
||||
use axum::{Json, Router, response::IntoResponse, routing::get};
|
||||
use reqwest::StatusCode;
|
||||
|
||||
mod get_users;
|
||||
|
||||
use crate::AppState;
|
||||
|
||||
pub type ApiResult<T> = Result<ApiResponse<T>, ApiError>;
|
||||
|
||||
pub struct ApiResponse<T>(pub StatusCode, pub T);
|
||||
|
||||
pub struct ApiError {
|
||||
pub status: StatusCode,
|
||||
pub error: &'static str,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
pub fn router() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route("/get_users", get(get_users::handler))
|
||||
}
|
||||
|
||||
impl IntoResponse for ApiError {
|
||||
fn into_response(self) -> axum::response::Response {
|
||||
let body = json!({ "error": self.error, "message": self.message });
|
||||
(self.status, Json(body)).into_response()
|
||||
}
|
||||
}
|
||||
impl<T: Serialize> IntoResponse for ApiResponse<T> {
|
||||
fn into_response(self) -> axum::response::Response {
|
||||
(self.0, Json(self.1)).into_response()
|
||||
}
|
||||
}
|
||||
6
koucha/src/bin/webapi/types.rs
Normal file
6
koucha/src/bin/webapi/types.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct User {
|
||||
pub name: String,
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue