feat(presentation): handlers, OpenAPI/Scalar, routes, extractors

This commit is contained in:
2026-05-18 00:07:07 +02:00
parent 4cab050ee8
commit 5d926e0f61
14 changed files with 516 additions and 1 deletions

View File

@@ -0,0 +1,56 @@
use axum::{extract::State, http::StatusCode, Json};
use api_types::{
requests::{LoginRequest, RegisterRequest},
responses::{AuthResponse, UserResponse},
};
use crate::{errors::AppError, extractors::{JwtClaims, ValidatedJson}, state::AppState};
#[utoipa::path(
post, path = "/api/v1/auth/register",
request_body = RegisterRequest,
responses(
(status = 201, description = "User registered", body = AuthResponse),
(status = 409, description = "Email already taken"),
(status = 422, description = "Validation error")
)
)]
pub async fn register(
State(state): State<AppState>,
ValidatedJson(req): ValidatedJson<RegisterRequest>,
) -> Result<(StatusCode, Json<AuthResponse>), AppError> {
let user = state.register_uc.execute(&req.email, &req.password).await?;
let token = state.token_issuer.issue(&user.id, &user.role).await.map_err(AppError::from)?;
Ok((StatusCode::CREATED, Json(AuthResponse { token, user: UserResponse::from_domain(&user) })))
}
#[utoipa::path(
post, path = "/api/v1/auth/login",
request_body = LoginRequest,
responses(
(status = 200, description = "Login successful", body = AuthResponse),
(status = 401, description = "Invalid credentials")
)
)]
pub async fn login(
State(state): State<AppState>,
ValidatedJson(req): ValidatedJson<LoginRequest>,
) -> Result<Json<AuthResponse>, AppError> {
let (user, token) = state.login_uc.execute(&req.email, &req.password).await?;
Ok(Json(AuthResponse { token, user: UserResponse::from_domain(&user) }))
}
#[utoipa::path(
get, path = "/api/v1/auth/me",
security(("bearer_token" = [])),
responses(
(status = 200, description = "Current user profile", body = UserResponse),
(status = 401, description = "Unauthorized")
)
)]
pub async fn me(
State(state): State<AppState>,
claims: JwtClaims,
) -> Result<Json<UserResponse>, AppError> {
let user = state.get_profile_uc.execute(&claims.user_id).await?;
Ok(Json(UserResponse::from_domain(&user)))
}

View File

@@ -0,0 +1,7 @@
use axum::{http::StatusCode, Json};
use serde_json::json;
#[utoipa::path(get, path = "/health", responses((status = 200, description = "Service is healthy")))]
pub async fn health() -> (StatusCode, Json<serde_json::Value>) {
(StatusCode::OK, Json(json!({ "status": "ok" })))
}

View File

@@ -0,0 +1,2 @@
pub mod auth;
pub mod health;