diff --git a/src/modes/server/api/item.rs b/src/modes/server/api/item.rs index f133eca..bc897b6 100644 --- a/src/modes/server/api/item.rs +++ b/src/modes/server/api/item.rs @@ -19,16 +19,18 @@ use crate::common::is_binary::is_binary; #[utoipa::path( get, path = "/api/item/", + summary = "List stored items", + description = "Retrieve a paginated list of stored items with their metadata and tags. Items can be filtered by tags and sorted by creation time. Each item includes comprehensive metadata extracted during storage such as file type, encoding, size, and custom tags for organization.", responses( (status = 200, description = "Successfully retrieved paginated list of items with metadata and tags", body = ApiResponse>), (status = 401, description = "Unauthorized - Invalid or missing authentication credentials"), (status = 500, description = "Internal server error - Failed to retrieve items from database") ), params( - ("tags" = Option, Query, description = "Comma-separated list of tags to filter by (e.g., 'important,work')"), - ("order" = Option, Query, description = "Sort order: 'newest' (default) or 'oldest'"), - ("start" = Option, Query, description = "Starting index for pagination (default: 0)"), - ("count" = Option, Query, description = "Maximum number of items to return (default: 100, max: 1000)") + ("tags" = Option, Query, description = "Comma-separated list of tags to filter by (e.g., 'important,work'). Only items that have ALL specified tags will be returned."), + ("order" = Option, Query, description = "Sort order for results: 'newest' (default, most recent first) or 'oldest' (oldest first)"), + ("start" = Option, Query, description = "Starting index for pagination (default: 0). Use this to skip items for pagination."), + ("count" = Option, Query, description = "Maximum number of items to return in this request (default: 100, maximum: 1000)") ), security( ("bearerAuth" = []) @@ -122,15 +124,17 @@ pub async fn handle_list_items( #[utoipa::path( post, path = "/api/item/", + summary = "Store new item", + description = "Create a new item by uploading content. The content will be automatically compressed, analyzed for metadata (file type, encoding, etc.), and stored with a unique identifier. Binary detection is performed automatically, and various metadata plugins extract information like line counts, file types, and system information.", responses( - (status = 201, description = "Successfully created new item", body = ApiResponse), - (status = 400, description = "Bad request - Invalid input data"), + (status = 201, description = "Successfully created new item with generated metadata and unique ID", body = ApiResponse), + (status = 400, description = "Bad request - Invalid input data or malformed content"), (status = 401, description = "Unauthorized - Invalid or missing authentication credentials"), - (status = 500, description = "Internal server error - Failed to create item") + (status = 500, description = "Internal server error - Failed to create item due to storage or processing error") ), request_body( content = String, - description = "Content to store as new item", + description = "Raw content to store as a new item. Can be text or binary data.", content_type = "application/octet-stream" ), security( @@ -158,15 +162,17 @@ pub async fn handle_post_item( #[utoipa::path( delete, path = "/api/item/{item_id}", + summary = "Delete stored item", + description = "Permanently delete an item and all its associated metadata, tags, and stored content. This operation cannot be undone. The item's compressed data file and all database records will be removed.", responses( - (status = 200, description = "Successfully deleted item and associated metadata"), - (status = 400, description = "Bad request - Invalid item ID"), + (status = 200, description = "Successfully deleted item and all associated metadata, tags, and content"), + (status = 400, description = "Bad request - Invalid item ID (must be a positive integer)"), (status = 401, description = "Unauthorized - Invalid or missing authentication credentials"), (status = 404, description = "Item not found - No item exists with the specified ID"), - (status = 500, description = "Internal server error - Failed to delete item") + (status = 500, description = "Internal server error - Failed to delete item due to database or filesystem error") ), params( - ("item_id" = i64, Path, description = "Unique identifier of the item to delete (must be positive)") + ("item_id" = i64, Path, description = "Unique identifier of the item to delete (must be a positive integer)") ), security( ("bearerAuth" = []) @@ -204,15 +210,17 @@ pub async fn handle_delete_item( #[utoipa::path( get, path = "/api/item/latest", + summary = "Get latest item with content", + description = "Retrieve the most recently stored item including its content and metadata. If tags are specified, returns the latest item that matches ALL the given tags. For text content, the actual content is included in the response. For binary content, only metadata is returned unless allow_binary is true.", responses( - (status = 200, description = "Successfully retrieved latest item with content and metadata. Content is included if item is text-based, otherwise only metadata is returned.", body = ApiResponse), + (status = 200, description = "Successfully retrieved latest item with content and metadata. Content is included if item is text-based or allow_binary is true.", body = ApiResponse), (status = 401, description = "Unauthorized - Invalid or missing authentication credentials"), - (status = 404, description = "Item not found - No items exist or no items match the specified tags"), - (status = 500, description = "Internal server error - Failed to retrieve item content") + (status = 404, description = "Item not found - No items exist in the database or no items match the specified tag criteria"), + (status = 500, description = "Internal server error - Failed to retrieve item content due to decompression or database error") ), params( - ("tags" = Option, Query, description = "Comma-separated list of tags to filter by (e.g., 'important,work'). If specified, returns the latest item matching ALL tags."), - ("allow_binary" = Option, Query, description = "Whether to include content for binary files (default: false). When false, binary files will only return metadata.") + ("tags" = Option, Query, description = "Comma-separated list of tags to filter by (e.g., 'important,work'). If specified, returns the latest item that has ALL the specified tags."), + ("allow_binary" = Option, Query, description = "Whether to include raw content for binary files (default: false). When false, binary files return only metadata. When true, binary content is included as a string.") ), security( ("bearerAuth" = []) @@ -268,16 +276,18 @@ pub async fn handle_get_item_latest( #[utoipa::path( get, path = "/api/item/{item_id}", + summary = "Get item with content", + description = "Retrieve a specific item by its ID including both content and metadata. The content is automatically decompressed and returned as a string for text files. Binary files return only metadata unless allow_binary is explicitly set to true.", responses( - (status = 200, description = "Successfully retrieved item with content and metadata. Content is included if item is text-based, otherwise only metadata is returned.", body = ApiResponse), - (status = 400, description = "Bad request - Invalid item ID"), + (status = 200, description = "Successfully retrieved item with content and metadata. Content is included if item is text-based or allow_binary is true.", body = ApiResponse), + (status = 400, description = "Bad request - Invalid item ID (must be a positive integer)"), (status = 401, description = "Unauthorized - Invalid or missing authentication credentials"), (status = 404, description = "Item not found - No item exists with the specified ID"), - (status = 500, description = "Internal server error - Failed to retrieve item content") + (status = 500, description = "Internal server error - Failed to retrieve item content due to decompression or database error") ), params( - ("item_id" = i64, Path, description = "Unique identifier of the item to retrieve (must be positive)"), - ("allow_binary" = Option, Query, description = "Whether to include content for binary files (default: false). When false, binary files will only return metadata.") + ("item_id" = i64, Path, description = "Unique identifier of the item to retrieve (must be a positive integer)"), + ("allow_binary" = Option, Query, description = "Whether to include raw content for binary files (default: false). When false, binary files return only metadata. When true, binary content is included as a string.") ), security( ("bearerAuth" = []) @@ -327,14 +337,16 @@ pub async fn handle_get_item( #[utoipa::path( get, path = "/api/item/latest/content", + summary = "Download latest item content", + description = "Download the raw content of the most recently stored item. The content is automatically decompressed and returned with the appropriate MIME type header for proper browser handling. If tags are specified, returns the latest item matching ALL the given tags.", responses( - (status = 200, description = "Successfully retrieved latest item raw content with appropriate MIME type header"), + (status = 200, description = "Successfully retrieved latest item raw content with appropriate Content-Type header set based on detected MIME type"), (status = 401, description = "Unauthorized - Invalid or missing authentication credentials"), - (status = 404, description = "Item not found - No items exist or no items match the specified tags"), - (status = 500, description = "Internal server error - Failed to retrieve item content") + (status = 404, description = "Item not found - No items exist in the database or no items match the specified tag criteria"), + (status = 500, description = "Internal server error - Failed to retrieve item content due to decompression or filesystem error") ), params( - ("tags" = Option, Query, description = "Comma-separated list of tags to filter by (e.g., 'important,work'). If specified, returns the latest item matching ALL tags.") + ("tags" = Option, Query, description = "Comma-separated list of tags to filter by (e.g., 'important,work'). If specified, returns the latest item that has ALL the specified tags.") ), security( ("bearerAuth" = []) @@ -385,15 +397,17 @@ pub async fn handle_get_item_latest_content( #[utoipa::path( get, path = "/api/item/{item_id}/content", + summary = "Download item content", + description = "Download the raw content of a specific item by its ID. The content is automatically decompressed and returned with the appropriate MIME type header for proper browser handling. This endpoint is ideal for downloading files or viewing content directly in the browser.", responses( - (status = 200, description = "Successfully retrieved item raw content with appropriate MIME type header"), - (status = 400, description = "Bad request - Invalid item ID"), + (status = 200, description = "Successfully retrieved item raw content with appropriate Content-Type header set based on detected MIME type"), + (status = 400, description = "Bad request - Invalid item ID (must be a positive integer)"), (status = 401, description = "Unauthorized - Invalid or missing authentication credentials"), (status = 404, description = "Item not found - No item exists with the specified ID"), - (status = 500, description = "Internal server error - Failed to retrieve item content") + (status = 500, description = "Internal server error - Failed to retrieve item content due to decompression or filesystem error") ), params( - ("item_id" = i64, Path, description = "Unique identifier of the item to retrieve (must be positive)") + ("item_id" = i64, Path, description = "Unique identifier of the item to retrieve content for (must be a positive integer)") ), security( ("bearerAuth" = []) @@ -542,14 +556,16 @@ async fn get_item_raw_content(item: &db::Item, data_dir: &PathBuf, conn: &mut ru #[utoipa::path( get, path = "/api/item/latest/meta", + summary = "Get latest item metadata", + description = "Retrieve comprehensive metadata for the most recently stored item. Metadata includes automatically extracted information such as file type, MIME type, encoding, line counts, file size, system information (user, hostname, etc.), and cryptographic hashes. If tags are specified, returns metadata for the latest item matching ALL the given tags.", responses( - (status = 200, description = "Successfully retrieved latest item metadata including file type, encoding, size, and other system information", body = ApiResponse>), + (status = 200, description = "Successfully retrieved latest item metadata as key-value pairs including file type, encoding, size, and system information", body = ApiResponse>), (status = 401, description = "Unauthorized - Invalid or missing authentication credentials"), - (status = 404, description = "Item not found - No items exist or no items match the specified tags"), - (status = 500, description = "Internal server error - Failed to retrieve item metadata") + (status = 404, description = "Item not found - No items exist in the database or no items match the specified tag criteria"), + (status = 500, description = "Internal server error - Failed to retrieve item metadata from database") ), params( - ("tags" = Option, Query, description = "Comma-separated list of tags to filter by (e.g., 'important,work'). If specified, returns the latest item matching ALL tags.") + ("tags" = Option, Query, description = "Comma-separated list of tags to filter by (e.g., 'important,work'). If specified, returns metadata for the latest item that has ALL the specified tags.") ), security( ("bearerAuth" = []) @@ -602,15 +618,17 @@ pub async fn handle_get_item_latest_meta( #[utoipa::path( get, path = "/api/item/{item_id}/meta", + summary = "Get item metadata", + description = "Retrieve comprehensive metadata for a specific item by its ID. Metadata includes automatically extracted information such as file type, MIME type, encoding, line counts, file size, system information (user, hostname, process ID, etc.), cryptographic hashes (SHA256, MD5), and performance metrics (read time, read rate).", responses( - (status = 200, description = "Successfully retrieved item metadata including file type, encoding, size, and other system information", body = ApiResponse>), - (status = 400, description = "Bad request - Invalid item ID"), + (status = 200, description = "Successfully retrieved item metadata as key-value pairs including file type, encoding, size, and system information", body = ApiResponse>), + (status = 400, description = "Bad request - Invalid item ID (must be a positive integer)"), (status = 401, description = "Unauthorized - Invalid or missing authentication credentials"), (status = 404, description = "Item not found - No item exists with the specified ID"), - (status = 500, description = "Internal server error - Failed to retrieve item metadata") + (status = 500, description = "Internal server error - Failed to retrieve item metadata from database") ), params( - ("item_id" = i64, Path, description = "Unique identifier of the item to retrieve metadata for (must be positive)") + ("item_id" = i64, Path, description = "Unique identifier of the item to retrieve metadata for (must be a positive integer)") ), security( ("bearerAuth" = []) diff --git a/src/modes/server/api/status.rs b/src/modes/server/api/status.rs index 2ca7f2d..390847e 100644 --- a/src/modes/server/api/status.rs +++ b/src/modes/server/api/status.rs @@ -11,10 +11,12 @@ use crate::meta_plugin::MetaPluginType; #[utoipa::path( get, path = "/api/status", + summary = "Get system status", + description = "Retrieve comprehensive system status information including database configuration, data storage paths, supported compression engines, available metadata plugins, and system capabilities. This endpoint is useful for health checks and system diagnostics.", responses( - (status = 200, description = "Successfully retrieved status information including database path, data directory, and supported plugins", body = ApiResponse), + (status = 200, description = "Successfully retrieved complete system status including database path, data directory, supported plugins, and system information", body = ApiResponse), (status = 401, description = "Unauthorized - Invalid or missing authentication credentials"), - (status = 500, description = "Internal server error - Failed to retrieve status information") + (status = 500, description = "Internal server error - Failed to retrieve status information due to system error") ), security( ("bearerAuth" = []) diff --git a/src/modes/server/common.rs b/src/modes/server/common.rs index 6e92abb..ce109e3 100644 --- a/src/modes/server/common.rs +++ b/src/modes/server/common.rs @@ -42,27 +42,42 @@ pub struct AppState { } #[derive(Serialize, Deserialize, ToSchema)] +#[schema(description = "Standard API response wrapper containing success status, data payload, and error information")] pub struct ApiResponse { + #[schema(description = "Indicates whether the API request was successful")] pub success: bool, + #[schema(description = "The response data payload, present when success is true")] pub data: Option, + #[schema(description = "Error message describing what went wrong, present when success is false")] pub error: Option, } #[derive(Serialize, Deserialize, ToSchema)] +#[schema(description = "Complete information about a stored item including metadata and tags")] pub struct ItemInfo { + #[schema(description = "Unique identifier for the item", example = 42)] pub id: i64, + #[schema(description = "ISO 8601 timestamp when the item was created", example = "2023-12-01T15:30:45Z")] pub ts: String, + #[schema(description = "Size of the original content in bytes before compression", example = 1024)] pub size: Option, + #[schema(description = "Compression algorithm used to store the item", example = "gzip")] pub compression: String, + #[schema(description = "List of tags associated with this item for categorization", example = json!(["important", "work", "document"]))] pub tags: Vec, + #[schema(description = "Key-value pairs of metadata extracted from the content (file type, encoding, etc.)", example = json!({"file.mime": "text/plain", "file.encoding": "utf-8", "line_count": "42"}))] pub metadata: HashMap, } #[derive(Serialize, Deserialize, ToSchema)] +#[schema(description = "Item information including content and metadata, with binary detection")] pub struct ItemContentInfo { #[serde(flatten)] + #[schema(description = "Key-value pairs of metadata extracted from the content", example = json!({"file.mime": "text/plain", "file.encoding": "utf-8", "line_count": "42"}))] pub metadata: HashMap, + #[schema(description = "The actual content as a string if it's text-based and allow_binary is true for binary content, null otherwise", example = "Hello, world!\nThis is the content of the file.")] pub content: Option, + #[schema(description = "Whether the content is detected as binary data (images, executables, etc.)", example = false)] pub binary: bool, }