Add docker compose files & Fix routes

This commit is contained in:
2025-11-13 02:32:35 +03:00
parent f9a1609e0c
commit 86d7545f7c
4 changed files with 60 additions and 62 deletions

1
.gitignore vendored
View File

@ -1,7 +1,6 @@
# my gitignore # my gitignore
todo.md todo.md
.env .env
compose.yaml
# ---> Rust # ---> Rust
# Generated by Cargo # Generated by Cargo

9
compose.yaml Normal file
View File

@ -0,0 +1,9 @@
services:
database:
image: docker.io/postgres:17
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- ${POSTGRES_PORT}:${POSTGRES_PORT}

6
example.env Normal file
View File

@ -0,0 +1,6 @@
POSTGRES_DB=server-db
POSTGRES_USER=axum-user
POSTGRES_PASSWORD=my-cool-pass
POSTGRES_PORT=5432
POSTGRES_HOST=localhost
DATABASE_URL=postgres://axum-user:my-cool-pass@localhost:5432/server-db

View File

@ -2,10 +2,10 @@ use axum::{
Json, Json,
extract::{Query, State}, extract::{Query, State},
response::IntoResponse, response::IntoResponse,
routing::{delete, get, post}, routing::{get, post},
}; };
use sqlx::PgPool; use sqlx::PgPool;
use std::fs; use std::{env, fs};
use tokio::net::TcpListener; use tokio::net::TcpListener;
#[derive(Clone)] #[derive(Clone)]
@ -51,7 +51,17 @@ pub struct GetGameQuery {
fn database_url() -> String { fn database_url() -> String {
let _ = dotenvy::dotenv(); let _ = dotenvy::dotenv();
let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL should be set"); let database_url = format!(
"postgres://{}:{}@{}:{}/{}",
env::var("POSTGRES_USER").unwrap(),
env::var("POSTGRES_PASSWORD").unwrap(),
env::var("POSTGRES_HOST").unwrap(),
env::var("POSTGRES_PORT").unwrap(),
env::var("POSTGRES_DB").unwrap(),
);
if database_url != env::var("DATABASE_URL").unwrap() {
panic!("DATABASE_URL is not set correctly");
}
println!("DATABASE_URL={database_url}"); println!("DATABASE_URL={database_url}");
database_url database_url
} }
@ -68,7 +78,7 @@ async fn create_table(pool: &PgPool) {
fn router(state: AppState) -> axum::Router { fn router(state: AppState) -> axum::Router {
axum::Router::new() axum::Router::new()
.route("/api/games", get(games_list).post(add_game)) .route("/api/games", get(games_list).post(insert_game))
.route("/api/games/{id}", post(insert_game).delete(delete_game)) .route("/api/games/{id}", post(insert_game).delete(delete_game))
.with_state(state) .with_state(state)
} }
@ -89,10 +99,7 @@ async fn main() {
axum::serve(listener, router(state)).await.unwrap(); axum::serve(listener, router(state)).await.unwrap();
} }
async fn games_list( async fn games_list(State(state): State<AppState>) -> impl IntoResponse {
State(state): State<AppState>,
Query(query): Query<GetGameQuery>,
) -> impl IntoResponse {
let games: Vec<Game> = sqlx::query_as!(Game, "SELECT * FROM games") let games: Vec<Game> = sqlx::query_as!(Game, "SELECT * FROM games")
.fetch_all(&state.pool) .fetch_all(&state.pool)
.await .await
@ -101,63 +108,40 @@ async fn games_list(
Json(games) Json(games)
} }
async fn add_game(
State(state): State<AppState>,
Json(game): Json<CreateGame>,
) -> impl IntoResponse {
let result = sqlx::query!(
"INSERT INTO games (name, publishing_house, developer, description, multiplayer, is_free_to_play)
VALUES ($1, $2, $3, $4, $5, $6)",
game.name,
game.publishing_house,
game.developer,
game.description,
game.multiplayer,
game.is_free_to_play,
)
.execute(&state.pool)
.await;
match result {
Ok(_) => axum::http::StatusCode::CREATED,
Err(_) => axum::http::StatusCode::INTERNAL_SERVER_ERROR,
}
}
async fn insert_game( async fn insert_game(
State(state): State<AppState>, State(state): State<AppState>,
Query(query): Query<GetGameQuery>,
Json(game): Json<CreateGame>, Json(game): Json<CreateGame>,
) -> impl IntoResponse { ) -> impl IntoResponse {
sqlx::query!( let sql_up = if query.id.is_some() {
"INSERT INTO games(name, publishing_house, developer, description, multiplayer, is_free_to_play) VALUES ($1, $2, $3, $4, $5, $6)", "UPDATE games SET name=$1, publishing_house=$2, developer=$3, description=$4, multiplayer=$5, is_free_to_play=$6 WHERE id=$7"
game.name, } else {
game.publishing_house, "INSERT INTO games(name, publishing_house, developer, description, multiplayer, is_free_to_play) VALUES ($1, $2, $3, $4, $5, $6)"
game.developer, };
game.description,
game.multiplayer, let mut sql_query = sqlx::query(sql_up)
game.is_free_to_play, .bind(game.name)
) .bind(game.publishing_house)
.bind(game.developer)
.bind(game.description)
.bind(game.multiplayer)
.bind(game.is_free_to_play);
if let Some(id) = query.id {
sql_query = sql_query.bind(id);
}
sql_query.execute(&state.pool).await.unwrap();
axum::http::StatusCode::CREATED
}
use axum::extract::Path;
async fn delete_game(State(state): State<AppState>, Path(id): Path<i32>) -> impl IntoResponse {
sqlx::query!("DELETE FROM games WHERE id = $1", id)
.execute(&state.pool) .execute(&state.pool)
.await .await
.unwrap(); .unwrap();
axum::http::StatusCode::OK axum::http::StatusCode::OK
} }
async fn delete_game(
State(state): State<AppState>,
Query(query): Query<GetGameQuery>,
) -> impl IntoResponse {
if let Some(id) = query.id {
let result = sqlx::query!("DELETE FROM games WHERE id = $1", id)
.execute(&state.pool)
.await;
match result {
Ok(_) => axum::http::StatusCode::OK,
Err(_) => axum::http::StatusCode::INTERNAL_SERVER_ERROR,
}
} else {
axum::http::StatusCode::BAD_REQUEST
}
}