feat(openapi): add search and people endpoints to Swagger/Scalar
This commit is contained in:
@@ -1,25 +1,34 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use utoipa::{IntoParams, ToSchema};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
pub struct SearchQueryParams {
|
pub struct SearchQueryParams {
|
||||||
|
/// Free-text query matched across title, cast, crew, genres and keywords.
|
||||||
pub q: Option<String>,
|
pub q: Option<String>,
|
||||||
|
/// Filter by genre name (exact match, case-sensitive).
|
||||||
pub genre: Option<String>,
|
pub genre: Option<String>,
|
||||||
|
/// Filter by release year.
|
||||||
pub year: Option<u16>,
|
pub year: Option<u16>,
|
||||||
|
/// Filter by person ID (UUID).
|
||||||
pub person_id: Option<Uuid>,
|
pub person_id: Option<Uuid>,
|
||||||
|
/// Filter crew results by department (e.g. "Directing", "Writing").
|
||||||
pub department: Option<String>,
|
pub department: Option<String>,
|
||||||
|
/// Filter by original language code (e.g. "en", "fr").
|
||||||
pub language: Option<String>,
|
pub language: Option<String>,
|
||||||
|
/// Max results to return (default 20).
|
||||||
pub limit: Option<u32>,
|
pub limit: Option<u32>,
|
||||||
|
/// Offset for pagination (default 0).
|
||||||
pub offset: Option<u32>,
|
pub offset: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, ToSchema)]
|
||||||
pub struct SearchResponse {
|
pub struct SearchResponse {
|
||||||
pub movies: PaginatedMovieHits,
|
pub movies: PaginatedMovieHits,
|
||||||
pub people: PaginatedPersonHits,
|
pub people: PaginatedPersonHits,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, ToSchema)]
|
||||||
pub struct PaginatedMovieHits {
|
pub struct PaginatedMovieHits {
|
||||||
pub items: Vec<MovieSearchHitDto>,
|
pub items: Vec<MovieSearchHitDto>,
|
||||||
pub total_count: u64,
|
pub total_count: u64,
|
||||||
@@ -27,7 +36,7 @@ pub struct PaginatedMovieHits {
|
|||||||
pub offset: u32,
|
pub offset: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, ToSchema)]
|
||||||
pub struct PaginatedPersonHits {
|
pub struct PaginatedPersonHits {
|
||||||
pub items: Vec<PersonSearchHitDto>,
|
pub items: Vec<PersonSearchHitDto>,
|
||||||
pub total_count: u64,
|
pub total_count: u64,
|
||||||
@@ -35,7 +44,7 @@ pub struct PaginatedPersonHits {
|
|||||||
pub offset: u32,
|
pub offset: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, ToSchema)]
|
||||||
pub struct MovieSearchHitDto {
|
pub struct MovieSearchHitDto {
|
||||||
pub movie_id: Uuid,
|
pub movie_id: Uuid,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
@@ -45,7 +54,7 @@ pub struct MovieSearchHitDto {
|
|||||||
pub genres: Vec<String>,
|
pub genres: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, ToSchema)]
|
||||||
pub struct PersonSearchHitDto {
|
pub struct PersonSearchHitDto {
|
||||||
pub person_id: Uuid,
|
pub person_id: Uuid,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -54,7 +63,7 @@ pub struct PersonSearchHitDto {
|
|||||||
pub known_for_titles: Vec<String>,
|
pub known_for_titles: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, ToSchema)]
|
||||||
pub struct PersonDto {
|
pub struct PersonDto {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub external_id: String,
|
pub external_id: String,
|
||||||
@@ -63,14 +72,14 @@ pub struct PersonDto {
|
|||||||
pub profile_path: Option<String>,
|
pub profile_path: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, ToSchema)]
|
||||||
pub struct PersonCreditsDto {
|
pub struct PersonCreditsDto {
|
||||||
pub person: PersonDto,
|
pub person: PersonDto,
|
||||||
pub cast: Vec<CastCreditDto>,
|
pub cast: Vec<CastCreditDto>,
|
||||||
pub crew: Vec<CrewCreditDto>,
|
pub crew: Vec<CrewCreditDto>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, ToSchema)]
|
||||||
pub struct CastCreditDto {
|
pub struct CastCreditDto {
|
||||||
pub movie_id: Uuid,
|
pub movie_id: Uuid,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
@@ -79,7 +88,7 @@ pub struct CastCreditDto {
|
|||||||
pub poster_path: Option<String>,
|
pub poster_path: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, ToSchema)]
|
||||||
pub struct CrewCreditDto {
|
pub struct CrewCreditDto {
|
||||||
pub movie_id: Uuid,
|
pub movie_id: Uuid,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
|||||||
@@ -1097,6 +1097,14 @@ pub async fn export_diary(
|
|||||||
// Search and person endpoints are intentionally public — browsing the catalog
|
// Search and person endpoints are intentionally public — browsing the catalog
|
||||||
// and people profiles does not require authentication.
|
// and people profiles does not require authentication.
|
||||||
|
|
||||||
|
#[utoipa::path(
|
||||||
|
get, path = "/api/v1/search",
|
||||||
|
params(api_types::search::SearchQueryParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, body = api_types::search::SearchResponse),
|
||||||
|
),
|
||||||
|
tag = "search",
|
||||||
|
)]
|
||||||
pub async fn get_search(
|
pub async fn get_search(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Query(params): Query<SearchQueryParams>,
|
Query(params): Query<SearchQueryParams>,
|
||||||
@@ -1151,6 +1159,15 @@ pub async fn get_search(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[utoipa::path(
|
||||||
|
get, path = "/api/v1/people/{id}",
|
||||||
|
params(("id" = Uuid, Path, description = "Person ID")),
|
||||||
|
responses(
|
||||||
|
(status = 200, body = api_types::search::PersonDto),
|
||||||
|
(status = 404, description = "Person not found"),
|
||||||
|
),
|
||||||
|
tag = "search",
|
||||||
|
)]
|
||||||
pub async fn get_person_handler(
|
pub async fn get_person_handler(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path(id): Path<uuid::Uuid>,
|
Path(id): Path<uuid::Uuid>,
|
||||||
@@ -1171,6 +1188,15 @@ pub async fn get_person_handler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[utoipa::path(
|
||||||
|
get, path = "/api/v1/people/{id}/credits",
|
||||||
|
params(("id" = Uuid, Path, description = "Person ID")),
|
||||||
|
responses(
|
||||||
|
(status = 200, body = api_types::search::PersonCreditsDto),
|
||||||
|
(status = 404, description = "Person not found"),
|
||||||
|
),
|
||||||
|
tag = "search",
|
||||||
|
)]
|
||||||
pub async fn get_person_credits_handler(
|
pub async fn get_person_credits_handler(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path(id): Path<uuid::Uuid>,
|
Path(id): Path<uuid::Uuid>,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ mod auth;
|
|||||||
mod diary;
|
mod diary;
|
||||||
mod import;
|
mod import;
|
||||||
mod movies;
|
mod movies;
|
||||||
|
mod search;
|
||||||
mod social;
|
mod social;
|
||||||
mod users;
|
mod users;
|
||||||
|
|
||||||
@@ -36,6 +37,7 @@ fn build() -> utoipa::openapi::OpenApi {
|
|||||||
api.merge(movies::MoviesDoc::openapi());
|
api.merge(movies::MoviesDoc::openapi());
|
||||||
api.merge(users::UsersDoc::openapi());
|
api.merge(users::UsersDoc::openapi());
|
||||||
api.merge(import::ImportDoc::openapi());
|
api.merge(import::ImportDoc::openapi());
|
||||||
|
api.merge(search::SearchDoc::openapi());
|
||||||
#[cfg(feature = "federation")]
|
#[cfg(feature = "federation")]
|
||||||
api.merge(social::SocialDoc::openapi());
|
api.merge(social::SocialDoc::openapi());
|
||||||
SecurityAddon.modify(&mut api);
|
SecurityAddon.modify(&mut api);
|
||||||
|
|||||||
29
crates/presentation/src/openapi/search.rs
Normal file
29
crates/presentation/src/openapi/search.rs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
use api_types::search::{
|
||||||
|
CastCreditDto, CrewCreditDto, MovieSearchHitDto, PaginatedMovieHits, PaginatedPersonHits,
|
||||||
|
PersonCreditsDto, PersonDto, PersonSearchHitDto, SearchResponse,
|
||||||
|
};
|
||||||
|
use utoipa::OpenApi;
|
||||||
|
|
||||||
|
#[derive(OpenApi)]
|
||||||
|
#[openapi(
|
||||||
|
paths(
|
||||||
|
crate::handlers::api::get_search,
|
||||||
|
crate::handlers::api::get_person_handler,
|
||||||
|
crate::handlers::api::get_person_credits_handler,
|
||||||
|
),
|
||||||
|
components(schemas(
|
||||||
|
SearchResponse,
|
||||||
|
PaginatedMovieHits,
|
||||||
|
PaginatedPersonHits,
|
||||||
|
MovieSearchHitDto,
|
||||||
|
PersonSearchHitDto,
|
||||||
|
PersonDto,
|
||||||
|
PersonCreditsDto,
|
||||||
|
CastCreditDto,
|
||||||
|
CrewCreditDto,
|
||||||
|
)),
|
||||||
|
tags(
|
||||||
|
(name = "search", description = "Full-text search across movies and people"),
|
||||||
|
),
|
||||||
|
)]
|
||||||
|
pub struct SearchDoc;
|
||||||
Reference in New Issue
Block a user