use utoipa::openapi::{self, tag::TagBuilder, InfoBuilder}; use utoipa::OpenApi; pub struct ApiDoc; impl OpenApi for ApiDoc { fn openapi() -> openapi::OpenApi { let mut doc = crate::routes::health::HealthApiDoc::openapi(); doc.merge(crate::routes::auth::AuthApiDoc::openapi()); doc.merge(crate::routes::documents::DocumentsApiDoc::openapi()); doc.merge(crate::routes::folders::FoldersApiDoc::openapi()); doc.merge(crate::routes::tags::TagsApiDoc::openapi()); doc.merge(crate::routes::correspondents::CorrespondentsApiDoc::openapi()); doc.merge(crate::routes::profile::ProfileApiDoc::openapi()); doc.info = InfoBuilder::new() .title("Papercrate API") .version(env!("CARGO_PKG_VERSION")) .build(); doc.tags = Some(vec![ TagBuilder::new() .name("Health") .description(Some("Service health")) .build(), TagBuilder::new() .name("Auth") .description(Some("Authentication")) .build(), TagBuilder::new() .name("Documents") .description(Some("Document management")) .build(), TagBuilder::new() .name("Assets") .description(Some("Document assets")) .build(), TagBuilder::new() .name("Folders") .description(Some("Folder management")) .build(), TagBuilder::new() .name("Tags") .description(Some("Tag catalog")) .build(), TagBuilder::new() .name("Correspondents") .description(Some("Correspondent catalog")) .build(), TagBuilder::new() .name("Profile") .description(Some("User profile and WebDAV tokens")) .build(), ]); doc } } pub mod schemas { pub use crate::auth::passkeys::{ AuthenticationChallengeResponse, PasskeyLoginFinishPayload, PasskeyLoginStartPayload, PasskeyRegistrationFinishPayload, PasskeySummary, RegistrationChallengeResponse, }; pub use crate::auth::AuthenticatedUser; pub use crate::documents::asset::{ DocumentAssetDetailResponse, DocumentAssetObjectResponse, DocumentAssetResponse, DocumentVersionDetailResponse, DocumentVersionResponse, }; pub use crate::documents::correspondents::DocumentCorrespondentResponse; pub use crate::models::ApiTokenCapability; pub use crate::routes::auth::{ ApiTokenExchangeRequest, LoginRequest, LoginResponse, LoginResponseVariants, SignupFinishRequest, SignupStartRequest, SignupStartResponse, TenantListResponse, TenantSelectionRequest, TenantSelectionResponse, TenantSnippet, }; pub use crate::routes::correspondents::{ CorrespondentSummary, CorrespondentUsage, CreateCorrespondentRequest, UpdateCorrespondentRequest, }; pub use crate::routes::documents::{ AssetObjectsQuery, AssetRequestQuery, AssignCorrespondentsRequest, AssignTagsRequest, BulkCorrespondentAction, BulkCorrespondentResponse, BulkCorrespondentsRequest, BulkMoveRequest, BulkMoveResponse, BulkReanalyzeResponse, BulkReanalyzeSelectionRequest, BulkTagAction, BulkTagRequest, BulkTagResponse, CorrespondentAssignmentInput, DocumentCheckQuery, DocumentCheckResponse, DocumentDetailResponse, DocumentListQuery, DocumentMetadataUpdate, DocumentResponse, DocumentStatusFilter, MoveDocumentRequest, RestoreDocumentRequest, TagResponse, UpdateDocumentRequest, UploadDocumentForm, }; pub use crate::routes::folders::{ CreateFolderRequest, EnsureFolderPathRequest, FolderContentsQuery, FolderContentsResponse, FolderInfo, FolderResponse, UpdateFolderRequest, }; pub use crate::routes::profile::{ ApiTokenCreatedResponse, ApiTokenResponse, CreateApiTokenRequest, RevokePasskeyQuery, UpdateApiTokenCapabilitiesRequest, }; pub use crate::routes::tags::{CreateTagRequest, TagCatalogEntry, UpdateTagRequest}; } #[cfg(test)] mod tests { use super::ApiDoc; use utoipa::OpenApi; #[test] fn openapi_serializes() { let spec = ApiDoc::openapi(); let _ = serde_json::to_string(&spec).expect("serialize openapi"); } }