Files
imphnen-backend-service/imphnen-dimentorin/src/articles/infrastructure/http/handlers/query_handlers.rs
T

108 lines
3.5 KiB
Rust

use super::super::dto::{ArticleDetailDto, ArticleListItemDto};
use crate::articles::domain::ArticleService;
use axum::{
extract::{Path, Query},
response::IntoResponse,
Extension,
};
use imphnen_libs::AppState;
use imphnen_utils::{ApiPaginated, ApiSuccess, AppError};
use paginator_utils::{PaginatorResponse, PaginatorResponseMeta};
use serde::Deserialize;
use std::sync::Arc;
use uuid::Uuid;
#[derive(Deserialize)]
pub struct ArticleListQuery {
pub page: Option<u64>,
pub per_page: Option<u64>,
pub category: Option<String>,
}
#[utoipa::path(
get,
path = "/v1/dimentorin/articles",
params(
("page" = Option<u64>, Query, description = "Page number"),
("per_page" = Option<u64>, Query, description = "Items per page"),
("category" = Option<String>, Query, description = "Filter by category"),
),
responses(
(status = 200, description = "Articles retrieved successfully", body = Vec<ArticleListItemDto>),
(status = 500, description = "Internal server error")
),
tag = "Articles"
)]
pub async fn get_articles_list(
Extension(_state): Extension<AppState>,
Extension(service): Extension<Arc<dyn ArticleService>>,
Query(q): Query<ArticleListQuery>,
) -> Result<impl IntoResponse, AppError> {
let page = q.page.unwrap_or(1).max(1);
let per_page = q.per_page.unwrap_or(10).clamp(1, 100);
let result = service.list(page, per_page, q.category).await?;
let mapped = PaginatorResponse {
data: result.data.into_iter().map(ArticleListItemDto::from).collect(),
meta: result.meta,
};
Ok(ApiPaginated(mapped))
}
#[utoipa::path(
get,
path = "/v1/dimentorin/articles/{id}",
params(("id" = String, Path, description = "Article ID")),
responses(
(status = 200, description = "Article retrieved successfully", body = ArticleDetailDto),
(status = 404, description = "Article not found"),
(status = 500, description = "Internal server error")
),
tag = "Articles"
)]
pub async fn get_article_by_id(
Extension(_state): Extension<AppState>,
Extension(service): Extension<Arc<dyn ArticleService>>,
Path(id): Path<String>,
) -> Result<impl IntoResponse, AppError> {
let uuid = Uuid::parse_str(&id)
.map_err(|_| AppError::BadRequestError("Invalid article ID".to_string()))?;
let dto = ArticleDetailDto::from(service.get_by_id(uuid).await?);
Ok(ApiSuccess(dto))
}
#[utoipa::path(
get,
path = "/v1/dimentorin/articles/slug/{slug}",
params(("slug" = String, Path, description = "Article slug")),
responses(
(status = 200, description = "Article retrieved successfully", body = ArticleDetailDto),
(status = 404, description = "Article not found"),
(status = 500, description = "Internal server error")
),
tag = "Articles"
)]
pub async fn get_article_by_slug(
Extension(_state): Extension<AppState>,
Extension(service): Extension<Arc<dyn ArticleService>>,
Path(slug): Path<String>,
) -> Result<impl IntoResponse, AppError> {
let dto = ArticleDetailDto::from(service.get_by_slug(&slug).await?);
Ok(ApiSuccess(dto))
}
#[utoipa::path(
get,
path = "/v1/dimentorin/articles/categories",
responses(
(status = 200, description = "Article categories retrieved successfully"),
(status = 500, description = "Internal server error")
),
tag = "Articles"
)]
pub async fn get_article_categories(
Extension(_state): Extension<AppState>,
Extension(service): Extension<Arc<dyn ArticleService>>,
) -> Result<impl IntoResponse, AppError> {
let cats = service.categories().await?;
Ok(ApiSuccess(cats))
}