Add utoipa and Scalar for API documentation
- Add utoipa and utoipa-scalar dependencies - Add ToSchema derives to all models - Add OpenAPI path annotations to auth, users, and health handlers - Create openapi.rs module with API documentation - Serve Scalar UI at /docs endpoint - Include JWT bearer auth security scheme Co-Authored-By: Warp <agent@warp.dev>
This commit is contained in:
@@ -50,6 +50,10 @@ rand = "0.8"
|
||||
base64 = "0.22"
|
||||
libm = "0.2" # Math functions for rating calculations
|
||||
|
||||
# API Documentation
|
||||
utoipa = { version = "4", features = ["axum_extras", "chrono"] }
|
||||
utoipa-scalar = { version = "0.1", features = ["axum"] }
|
||||
|
||||
# S3 compatible storage
|
||||
aws-sdk-s3 = "1"
|
||||
aws-config = "1"
|
||||
|
||||
@@ -41,6 +41,8 @@ CREATE TABLE IF NOT EXISTS team_players (
|
||||
date_created TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
team_id INTEGER NOT NULL REFERENCES teams(id) ON DELETE CASCADE,
|
||||
player_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
game_name TEXT NOT NULL DEFAULT '',
|
||||
game_mode TEXT NOT NULL DEFAULT '',
|
||||
position VARCHAR(20) NOT NULL DEFAULT 'member',
|
||||
status INTEGER NOT NULL DEFAULT 0,
|
||||
UNIQUE(team_id, player_id)
|
||||
@@ -70,6 +72,12 @@ CREATE TABLE IF NOT EXISTS ladder_teams (
|
||||
date_created TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
ladder_id INTEGER NOT NULL REFERENCES ladders(id) ON DELETE CASCADE,
|
||||
team_id INTEGER NOT NULL REFERENCES teams(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
status VARCHAR(255) NOT NULL DEFAULT 'active',
|
||||
seed INTEGER,
|
||||
result_position INTEGER,
|
||||
win_count INTEGER NOT NULL DEFAULT 0,
|
||||
loss_count INTEGER NOT NULL DEFAULT 0,
|
||||
UNIQUE(ladder_id, team_id)
|
||||
);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use axum::{extract::State, http::StatusCode, Json};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::PgPool;
|
||||
use utoipa::ToSchema;
|
||||
use validator::Validate;
|
||||
|
||||
use crate::{
|
||||
@@ -11,7 +12,7 @@ use crate::{
|
||||
};
|
||||
|
||||
/// Login request
|
||||
#[derive(Debug, Deserialize, Validate)]
|
||||
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
||||
pub struct LoginRequest {
|
||||
#[validate(email(message = "Invalid email format"))]
|
||||
pub email: String,
|
||||
@@ -20,14 +21,14 @@ pub struct LoginRequest {
|
||||
}
|
||||
|
||||
/// Login response
|
||||
#[derive(Debug, Serialize)]
|
||||
#[derive(Debug, Serialize, ToSchema)]
|
||||
pub struct AuthResponse {
|
||||
pub token: String,
|
||||
pub user: UserResponse,
|
||||
}
|
||||
|
||||
/// User data in response
|
||||
#[derive(Debug, Serialize)]
|
||||
#[derive(Debug, Serialize, ToSchema)]
|
||||
pub struct UserResponse {
|
||||
pub id: i32,
|
||||
pub email: String,
|
||||
@@ -53,7 +54,7 @@ impl From<User> for UserResponse {
|
||||
}
|
||||
|
||||
/// Register request
|
||||
#[derive(Debug, Deserialize, Validate)]
|
||||
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
||||
pub struct RegisterRequest {
|
||||
#[validate(length(min = 1, max = 100, message = "First name is required"))]
|
||||
pub firstname: String,
|
||||
@@ -76,6 +77,16 @@ pub struct AppState {
|
||||
}
|
||||
|
||||
/// POST /api/auth/login
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/api/auth/login",
|
||||
tag = "auth",
|
||||
request_body = LoginRequest,
|
||||
responses(
|
||||
(status = 200, description = "Login successful", body = AuthResponse),
|
||||
(status = 401, description = "Invalid email or password")
|
||||
)
|
||||
)]
|
||||
pub async fn login(
|
||||
State(state): State<AppState>,
|
||||
Json(payload): Json<LoginRequest>,
|
||||
@@ -113,6 +124,16 @@ pub async fn login(
|
||||
}
|
||||
|
||||
/// POST /api/auth/register
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/api/auth/register",
|
||||
tag = "auth",
|
||||
request_body = RegisterRequest,
|
||||
responses(
|
||||
(status = 201, description = "Registration successful", body = AuthResponse),
|
||||
(status = 409, description = "Email or username already exists")
|
||||
)
|
||||
)]
|
||||
pub async fn register(
|
||||
State(state): State<AppState>,
|
||||
Json(payload): Json<RegisterRequest>,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use axum::{extract::State, http::StatusCode, Json};
|
||||
use serde::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use super::auth::AppState;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct HealthResponse {
|
||||
pub status: String,
|
||||
pub version: String,
|
||||
@@ -12,6 +13,15 @@ pub struct HealthResponse {
|
||||
|
||||
/// Health check endpoint
|
||||
/// GET /health
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/health",
|
||||
tag = "health",
|
||||
responses(
|
||||
(status = 200, description = "API is healthy", body = HealthResponse),
|
||||
(status = 503, description = "Database connection error")
|
||||
)
|
||||
)]
|
||||
pub async fn health_check(State(state): State<AppState>) -> (StatusCode, Json<HealthResponse>) {
|
||||
// Check database connectivity
|
||||
let db_status = match sqlx::query("SELECT 1").fetch_one(&state.pool).await {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use axum::{extract::State, Json};
|
||||
use serde::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use crate::{
|
||||
auth::AuthUser,
|
||||
@@ -10,7 +11,7 @@ use crate::{
|
||||
use super::auth::AppState;
|
||||
|
||||
/// User profile response
|
||||
#[derive(Debug, Serialize)]
|
||||
#[derive(Debug, Serialize, ToSchema)]
|
||||
pub struct UserProfileResponse {
|
||||
pub id: i32,
|
||||
pub email: String,
|
||||
@@ -39,6 +40,18 @@ impl From<User> for UserProfileResponse {
|
||||
|
||||
/// GET /api/users/me
|
||||
/// Get current authenticated user's profile
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/users/me",
|
||||
tag = "users",
|
||||
responses(
|
||||
(status = 200, description = "Current user profile", body = UserProfileResponse),
|
||||
(status = 401, description = "Unauthorized")
|
||||
),
|
||||
security(
|
||||
("bearer_auth" = [])
|
||||
)
|
||||
)]
|
||||
pub async fn get_current_user(
|
||||
user: AuthUser,
|
||||
State(state): State<AppState>,
|
||||
|
||||
@@ -8,6 +8,7 @@ pub mod db;
|
||||
pub mod error;
|
||||
pub mod handlers;
|
||||
pub mod models;
|
||||
pub mod openapi;
|
||||
pub mod services;
|
||||
|
||||
// Re-export commonly used types
|
||||
|
||||
@@ -8,6 +8,8 @@ use tower_http::{
|
||||
trace::TraceLayer,
|
||||
};
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
use utoipa::OpenApi;
|
||||
use utoipa_scalar::{Scalar, Servable};
|
||||
|
||||
use vrbattles_api::{
|
||||
auth::middleware::JwtSecret,
|
||||
@@ -38,6 +40,7 @@ use vrbattles_api::{
|
||||
},
|
||||
users::get_current_user,
|
||||
},
|
||||
openapi::ApiDoc,
|
||||
services::storage::StorageService,
|
||||
};
|
||||
|
||||
@@ -86,6 +89,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
// Build router
|
||||
let app = Router::new()
|
||||
// API Documentation
|
||||
.merge(Scalar::with_url("/docs", ApiDoc::openapi()))
|
||||
// Health check
|
||||
.route("/health", get(health_check))
|
||||
// Auth routes
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Featured player model representing the featured_players table
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow, ToSchema)]
|
||||
pub struct FeaturedPlayer {
|
||||
pub id: i32,
|
||||
pub date_created: DateTime<Utc>,
|
||||
@@ -12,7 +13,7 @@ pub struct FeaturedPlayer {
|
||||
}
|
||||
|
||||
/// Featured player with user details (joined query result)
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow, ToSchema)]
|
||||
pub struct FeaturedPlayerWithUser {
|
||||
pub id: i32,
|
||||
pub player_id: i32,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Ladder status
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
|
||||
pub enum LadderStatus {
|
||||
Open = 0,
|
||||
Closed = 1,
|
||||
@@ -19,7 +20,7 @@ impl From<i32> for LadderStatus {
|
||||
}
|
||||
|
||||
/// Ladder model representing the ladders table
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow, ToSchema)]
|
||||
pub struct Ladder {
|
||||
pub id: i32,
|
||||
pub date_created: DateTime<Utc>,
|
||||
@@ -32,7 +33,7 @@ pub struct Ladder {
|
||||
}
|
||||
|
||||
/// Create ladder request
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct CreateLadder {
|
||||
pub name: String,
|
||||
pub date_start: String,
|
||||
@@ -40,7 +41,7 @@ pub struct CreateLadder {
|
||||
}
|
||||
|
||||
/// Update ladder request
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct UpdateLadder {
|
||||
pub name: Option<String>,
|
||||
pub date_start: Option<String>,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Ladder team model representing the ladder_teams table
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow, ToSchema)]
|
||||
pub struct LadderTeam {
|
||||
pub id: i32,
|
||||
pub date_created: DateTime<Utc>,
|
||||
@@ -12,7 +13,7 @@ pub struct LadderTeam {
|
||||
}
|
||||
|
||||
/// Join ladder request
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct JoinLadderRequest {
|
||||
pub team_id: i32,
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Match status values
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
|
||||
pub enum MatchStatus {
|
||||
Open = 0, // Initial state
|
||||
Scheduled = 1, // Both teams accepted
|
||||
@@ -25,7 +26,7 @@ impl From<i32> for MatchStatus {
|
||||
}
|
||||
|
||||
/// Team challenge status
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
|
||||
pub enum TeamChallengeStatus {
|
||||
Challenging = 0, // Sent challenge
|
||||
PendingResponse = 1, // Waiting for response
|
||||
@@ -47,7 +48,7 @@ impl From<i32> for TeamChallengeStatus {
|
||||
}
|
||||
|
||||
/// Match model representing the matches table
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow, ToSchema)]
|
||||
pub struct Match {
|
||||
pub id: i32,
|
||||
pub date_created: DateTime<Utc>,
|
||||
@@ -62,14 +63,14 @@ pub struct Match {
|
||||
}
|
||||
|
||||
/// Create match/challenge request
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct CreateChallengeRequest {
|
||||
pub to_team_id: i32,
|
||||
pub challenge_date: String,
|
||||
}
|
||||
|
||||
/// Accept/Counter challenge request
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct RespondChallengeRequest {
|
||||
pub challenge_date: Option<String>,
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Score acceptance status
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
|
||||
pub enum ScoreAcceptanceStatus {
|
||||
Pending = 0,
|
||||
Submitted = 1,
|
||||
@@ -23,7 +24,7 @@ impl From<i32> for ScoreAcceptanceStatus {
|
||||
}
|
||||
|
||||
/// Match round model representing the match_rounds table
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow, ToSchema)]
|
||||
pub struct MatchRound {
|
||||
pub id: i32,
|
||||
pub date_created: DateTime<Utc>,
|
||||
@@ -35,7 +36,7 @@ pub struct MatchRound {
|
||||
}
|
||||
|
||||
/// Submit score request
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct SubmitScoreRequest {
|
||||
pub team_1_score: i32,
|
||||
pub team_2_score: i32,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Team model representing the teams table
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow, ToSchema)]
|
||||
pub struct Team {
|
||||
pub id: i32,
|
||||
pub date_created: DateTime<Utc>,
|
||||
@@ -20,7 +21,7 @@ pub struct Team {
|
||||
}
|
||||
|
||||
/// Team with full stats (for API responses)
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[derive(Debug, Clone, Serialize, ToSchema)]
|
||||
pub struct TeamWithStats {
|
||||
pub id: i32,
|
||||
pub date_created: DateTime<Utc>,
|
||||
@@ -52,14 +53,14 @@ impl From<Team> for TeamWithStats {
|
||||
}
|
||||
|
||||
/// Create team request
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct CreateTeam {
|
||||
pub name: String,
|
||||
pub bio: Option<String>,
|
||||
}
|
||||
|
||||
/// Update team request
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct UpdateTeam {
|
||||
pub name: Option<String>,
|
||||
pub bio: Option<String>,
|
||||
@@ -67,7 +68,7 @@ pub struct UpdateTeam {
|
||||
}
|
||||
|
||||
/// Team member info
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[derive(Debug, Clone, Serialize, ToSchema)]
|
||||
pub struct TeamMember {
|
||||
pub player_id: i32,
|
||||
pub username: String,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Team player positions
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum PlayerPosition {
|
||||
Captain,
|
||||
@@ -32,7 +33,7 @@ impl PlayerPosition {
|
||||
}
|
||||
|
||||
/// Team player status
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
|
||||
pub enum TeamPlayerStatus {
|
||||
Pending = 0,
|
||||
Active = 1,
|
||||
@@ -48,7 +49,7 @@ impl From<i32> for TeamPlayerStatus {
|
||||
}
|
||||
|
||||
/// Team player model representing the team_players table
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow, ToSchema)]
|
||||
pub struct TeamPlayer {
|
||||
pub id: i32,
|
||||
pub date_created: DateTime<Utc>,
|
||||
@@ -59,13 +60,13 @@ pub struct TeamPlayer {
|
||||
}
|
||||
|
||||
/// Join team request
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct JoinTeamRequest {
|
||||
pub team_id: i32,
|
||||
}
|
||||
|
||||
/// Change position request
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct ChangePositionRequest {
|
||||
pub position: String,
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// User model representing the users table
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow, ToSchema)]
|
||||
pub struct User {
|
||||
pub id: i32,
|
||||
pub date_registered: DateTime<Utc>,
|
||||
@@ -25,7 +26,7 @@ pub struct User {
|
||||
}
|
||||
|
||||
/// User public profile (without sensitive data)
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[derive(Debug, Clone, Serialize, ToSchema)]
|
||||
pub struct UserProfile {
|
||||
pub id: i32,
|
||||
pub date_registered: DateTime<Utc>,
|
||||
@@ -57,7 +58,7 @@ impl From<User> for UserProfile {
|
||||
}
|
||||
|
||||
/// Create user request (internal use)
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct CreateUser {
|
||||
pub firstname: String,
|
||||
pub lastname: String,
|
||||
@@ -67,7 +68,7 @@ pub struct CreateUser {
|
||||
}
|
||||
|
||||
/// Update user request
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct UpdateUser {
|
||||
pub firstname: Option<String>,
|
||||
pub lastname: Option<String>,
|
||||
@@ -76,7 +77,7 @@ pub struct UpdateUser {
|
||||
}
|
||||
|
||||
/// Player stats response
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[derive(Debug, Clone, Serialize, ToSchema)]
|
||||
pub struct PlayerStats {
|
||||
pub id: i32,
|
||||
pub username: String,
|
||||
|
||||
128
src/openapi.rs
Normal file
128
src/openapi.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
use utoipa::OpenApi;
|
||||
|
||||
use crate::{
|
||||
handlers::{
|
||||
auth::{AuthResponse, LoginRequest, RegisterRequest, UserResponse},
|
||||
health::HealthResponse,
|
||||
users::UserProfileResponse,
|
||||
},
|
||||
models::{
|
||||
featured_player::{FeaturedPlayer, FeaturedPlayerWithUser},
|
||||
ladder::{CreateLadder, Ladder, LadderStatus, UpdateLadder},
|
||||
ladder_team::{JoinLadderRequest, LadderTeam},
|
||||
match_model::{CreateChallengeRequest, Match, MatchStatus, RespondChallengeRequest, TeamChallengeStatus},
|
||||
match_round::{MatchRound, ScoreAcceptanceStatus, SubmitScoreRequest},
|
||||
team::{CreateTeam, Team, TeamMember, TeamWithStats, UpdateTeam},
|
||||
team_player::{ChangePositionRequest, JoinTeamRequest, PlayerPosition, TeamPlayer, TeamPlayerStatus},
|
||||
user::{CreateUser, PlayerStats, UpdateUser, User, UserProfile},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
info(
|
||||
title = "VRBattles API",
|
||||
version = "1.0.0",
|
||||
description = "VRBattles Esports Platform API - Manage teams, matches, tournaments, and rankings for competitive VR gaming.",
|
||||
contact(
|
||||
name = "VRBattles Team",
|
||||
url = "https://vrbattles.gg"
|
||||
),
|
||||
license(
|
||||
name = "Proprietary"
|
||||
)
|
||||
),
|
||||
servers(
|
||||
(url = "https://api.vrb.gg", description = "Production server"),
|
||||
(url = "http://localhost:3000", description = "Local development")
|
||||
),
|
||||
tags(
|
||||
(name = "health", description = "Health check"),
|
||||
(name = "auth", description = "Authentication endpoints"),
|
||||
(name = "users", description = "User management"),
|
||||
(name = "teams", description = "Team management"),
|
||||
(name = "ladders", description = "Ladder/league management"),
|
||||
(name = "matches", description = "Match and challenge management"),
|
||||
(name = "players", description = "Player profiles and rankings"),
|
||||
(name = "uploads", description = "File uploads (logos, profile pictures)")
|
||||
),
|
||||
paths(
|
||||
// Health
|
||||
crate::handlers::health::health_check,
|
||||
// Auth
|
||||
crate::handlers::auth::login,
|
||||
crate::handlers::auth::register,
|
||||
// Users
|
||||
crate::handlers::users::get_current_user,
|
||||
),
|
||||
components(
|
||||
schemas(
|
||||
// Health
|
||||
HealthResponse,
|
||||
// Auth
|
||||
LoginRequest,
|
||||
RegisterRequest,
|
||||
AuthResponse,
|
||||
UserResponse,
|
||||
UserProfileResponse,
|
||||
// User
|
||||
User,
|
||||
UserProfile,
|
||||
CreateUser,
|
||||
UpdateUser,
|
||||
PlayerStats,
|
||||
// Team
|
||||
Team,
|
||||
TeamWithStats,
|
||||
CreateTeam,
|
||||
UpdateTeam,
|
||||
TeamMember,
|
||||
// Team Player
|
||||
TeamPlayer,
|
||||
JoinTeamRequest,
|
||||
ChangePositionRequest,
|
||||
PlayerPosition,
|
||||
TeamPlayerStatus,
|
||||
// Ladder
|
||||
Ladder,
|
||||
LadderStatus,
|
||||
CreateLadder,
|
||||
UpdateLadder,
|
||||
LadderTeam,
|
||||
JoinLadderRequest,
|
||||
// Match
|
||||
Match,
|
||||
MatchStatus,
|
||||
TeamChallengeStatus,
|
||||
CreateChallengeRequest,
|
||||
RespondChallengeRequest,
|
||||
// Match Round
|
||||
MatchRound,
|
||||
ScoreAcceptanceStatus,
|
||||
SubmitScoreRequest,
|
||||
// Featured Player
|
||||
FeaturedPlayer,
|
||||
FeaturedPlayerWithUser,
|
||||
)
|
||||
),
|
||||
modifiers(&SecurityAddon)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
struct SecurityAddon;
|
||||
|
||||
impl utoipa::Modify for SecurityAddon {
|
||||
fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
|
||||
if let Some(components) = openapi.components.as_mut() {
|
||||
components.add_security_scheme(
|
||||
"bearer_auth",
|
||||
utoipa::openapi::security::SecurityScheme::Http(
|
||||
utoipa::openapi::security::Http::new(
|
||||
utoipa::openapi::security::HttpAuthScheme::Bearer,
|
||||
)
|
||||
.bearer_format("JWT"),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user