feat(openapi): add search and people endpoints to Swagger/Scalar

This commit is contained in:
2026-05-12 18:50:33 +02:00
parent 67955c004d
commit 2640c99243
4 changed files with 76 additions and 10 deletions

View File

@@ -1,25 +1,34 @@
use serde::{Deserialize, Serialize};
use utoipa::{IntoParams, ToSchema};
use uuid::Uuid;
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, IntoParams)]
pub struct SearchQueryParams {
/// Free-text query matched across title, cast, crew, genres and keywords.
pub q: Option<String>,
/// Filter by genre name (exact match, case-sensitive).
pub genre: Option<String>,
/// Filter by release year.
pub year: Option<u16>,
/// Filter by person ID (UUID).
pub person_id: Option<Uuid>,
/// Filter crew results by department (e.g. "Directing", "Writing").
pub department: Option<String>,
/// Filter by original language code (e.g. "en", "fr").
pub language: Option<String>,
/// Max results to return (default 20).
pub limit: Option<u32>,
/// Offset for pagination (default 0).
pub offset: Option<u32>,
}
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, ToSchema)]
pub struct SearchResponse {
pub movies: PaginatedMovieHits,
pub people: PaginatedPersonHits,
}
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, ToSchema)]
pub struct PaginatedMovieHits {
pub items: Vec<MovieSearchHitDto>,
pub total_count: u64,
@@ -27,7 +36,7 @@ pub struct PaginatedMovieHits {
pub offset: u32,
}
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, ToSchema)]
pub struct PaginatedPersonHits {
pub items: Vec<PersonSearchHitDto>,
pub total_count: u64,
@@ -35,7 +44,7 @@ pub struct PaginatedPersonHits {
pub offset: u32,
}
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, ToSchema)]
pub struct MovieSearchHitDto {
pub movie_id: Uuid,
pub title: String,
@@ -45,7 +54,7 @@ pub struct MovieSearchHitDto {
pub genres: Vec<String>,
}
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, ToSchema)]
pub struct PersonSearchHitDto {
pub person_id: Uuid,
pub name: String,
@@ -54,7 +63,7 @@ pub struct PersonSearchHitDto {
pub known_for_titles: Vec<String>,
}
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, ToSchema)]
pub struct PersonDto {
pub id: Uuid,
pub external_id: String,
@@ -63,14 +72,14 @@ pub struct PersonDto {
pub profile_path: Option<String>,
}
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, ToSchema)]
pub struct PersonCreditsDto {
pub person: PersonDto,
pub cast: Vec<CastCreditDto>,
pub crew: Vec<CrewCreditDto>,
}
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, ToSchema)]
pub struct CastCreditDto {
pub movie_id: Uuid,
pub title: String,
@@ -79,7 +88,7 @@ pub struct CastCreditDto {
pub poster_path: Option<String>,
}
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, ToSchema)]
pub struct CrewCreditDto {
pub movie_id: Uuid,
pub title: String,

View File

@@ -1097,6 +1097,14 @@ pub async fn export_diary(
// Search and person endpoints are intentionally public — browsing the catalog
// 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(
State(state): State<AppState>,
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(
State(state): State<AppState>,
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(
State(state): State<AppState>,
Path(id): Path<uuid::Uuid>,

View File

@@ -2,6 +2,7 @@ mod auth;
mod diary;
mod import;
mod movies;
mod search;
mod social;
mod users;
@@ -36,6 +37,7 @@ fn build() -> utoipa::openapi::OpenApi {
api.merge(movies::MoviesDoc::openapi());
api.merge(users::UsersDoc::openapi());
api.merge(import::ImportDoc::openapi());
api.merge(search::SearchDoc::openapi());
#[cfg(feature = "federation")]
api.merge(social::SocialDoc::openapi());
SecurityAddon.modify(&mut api);

View 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;