Files
fastapi-toolsets/src/fastapi_toolsets/schemas.py
d3vyce 5a08ec2f57 feat: add faceted search in CrudFactory (#97)
* feat: add faceted search in CrudFactory

* feat: add filter_params_schema in CrudFactory

* fix: add missing Raises in build_search_filters docstring

* fix: faceted search

* fix: cov

* fix: documentation/filter_params
2026-02-26 15:23:07 +01:00

137 lines
3.2 KiB
Python

"""Base Pydantic schemas for API responses."""
from enum import Enum
from typing import Any, ClassVar, Generic, TypeVar
from pydantic import BaseModel, ConfigDict
__all__ = [
"ApiError",
"CursorPagination",
"ErrorResponse",
"OffsetPagination",
"Pagination",
"PaginatedResponse",
"PydanticBase",
"Response",
"ResponseStatus",
]
DataT = TypeVar("DataT")
class PydanticBase(BaseModel):
"""Base class for all Pydantic models with common configuration."""
model_config: ClassVar[ConfigDict] = ConfigDict(
from_attributes=True,
validate_assignment=True,
)
class ResponseStatus(str, Enum):
"""Standard API response status."""
SUCCESS = "SUCCESS"
FAIL = "FAIL"
class ApiError(PydanticBase):
"""Structured API error definition.
Used to define standard error responses with consistent format.
Attributes:
code: HTTP status code
msg: Short error message
desc: Detailed error description
err_code: Application-specific error code (e.g., "AUTH-401")
"""
code: int
msg: str
desc: str
err_code: str
data: Any | None = None
class BaseResponse(PydanticBase):
"""Base response structure for all API responses.
Attributes:
status: SUCCESS or FAIL
message: Human-readable message
error_code: Error code if status is FAIL, None otherwise
"""
status: ResponseStatus = ResponseStatus.SUCCESS
message: str = "Success"
error_code: str | None = None
class Response(BaseResponse, Generic[DataT]):
"""Generic API response with data payload.
Example:
```python
Response[UserRead](data=user, message="User retrieved")
```
"""
data: DataT | None = None
class ErrorResponse(BaseResponse):
"""Error response with additional description field.
Used for error responses that need more context.
"""
status: ResponseStatus = ResponseStatus.FAIL
description: str | None = None
data: Any | None = None
class OffsetPagination(PydanticBase):
"""Pagination metadata for offset-based list responses.
Attributes:
total_count: Total number of items across all pages
items_per_page: Number of items per page
page: Current page number (1-indexed)
has_more: Whether there are more pages
"""
total_count: int
items_per_page: int
page: int
has_more: bool
# Backward-compatible - will be removed in v2.0
Pagination = OffsetPagination
class CursorPagination(PydanticBase):
"""Pagination metadata for cursor-based list responses.
Attributes:
next_cursor: Encoded cursor for the next page, or None on the last page.
prev_cursor: Encoded cursor for the previous page, or None on the first page.
items_per_page: Number of items requested per page.
has_more: Whether there is at least one more page after this one.
"""
next_cursor: str | None
prev_cursor: str | None = None
items_per_page: int
has_more: bool
class PaginatedResponse(BaseResponse, Generic[DataT]):
"""Paginated API response for list endpoints."""
data: list[DataT]
pagination: OffsetPagination | CursorPagination
filter_attributes: dict[str, list[Any]] | None = None