🐛 fix(store.py): replace generic exception handling with custom exceptions to provide more specific error messages and status codes
🔀 merge(exceptions.py): add custom exceptions with status codes to handle specific errors in the store service 🔀 merge(service.py): replace ValueError with custom exceptions in the store service to provide more specific error messages and status codes
This commit is contained in:
parent
db275cffa2
commit
bbba05b49b
3 changed files with 42 additions and 21 deletions
|
|
@ -4,9 +4,11 @@ from uuid import UUID
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||||
from httpx import HTTPStatusError
|
from httpx import HTTPStatusError
|
||||||
|
|
||||||
from langflow.services.auth import utils as auth_utils
|
from langflow.services.auth import utils as auth_utils
|
||||||
from langflow.services.database.models.user.user import User
|
from langflow.services.database.models.user.user import User
|
||||||
from langflow.services.deps import get_settings_service, get_store_service
|
from langflow.services.deps import get_settings_service, get_store_service
|
||||||
|
from langflow.services.store.exceptions import CustomException
|
||||||
from langflow.services.store.schema import (
|
from langflow.services.store.schema import (
|
||||||
CreateComponentResponse,
|
CreateComponentResponse,
|
||||||
DownloadComponentResponse,
|
DownloadComponentResponse,
|
||||||
|
|
@ -127,17 +129,11 @@ async def get_components(
|
||||||
limit=limit,
|
limit=limit,
|
||||||
store_api_Key=store_api_Key,
|
store_api_Key=store_api_Key,
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except CustomException as exc:
|
||||||
if isinstance(exc, HTTPStatusError):
|
if isinstance(exc, ValueError):
|
||||||
if exc.response.status_code == 403:
|
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
||||||
raise HTTPException(status_code=403, detail="Forbidden")
|
|
||||||
elif isinstance(exc, ValueError):
|
|
||||||
if "Check your API key" in str(exc):
|
|
||||||
raise HTTPException(status_code=401, detail=str(exc))
|
|
||||||
elif "filter by likes" in str(exc) or "filter your components" in str(exc):
|
|
||||||
raise HTTPException(status_code=400, detail=str(exc))
|
|
||||||
|
|
||||||
raise HTTPException(status_code=500, detail=str(exc))
|
raise HTTPException(status_code=exc.status_code, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@router.get("/components/{component_id}", response_model=DownloadComponentResponse)
|
@router.get("/components/{component_id}", response_model=DownloadComponentResponse)
|
||||||
|
|
|
||||||
25
src/backend/langflow/services/store/exceptions.py
Normal file
25
src/backend/langflow/services/store/exceptions.py
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
class CustomException(Exception):
|
||||||
|
def __init__(self, detail, status_code):
|
||||||
|
super().__init__(detail)
|
||||||
|
self.status_code = status_code
|
||||||
|
|
||||||
|
|
||||||
|
# Define custom exceptions with status codes
|
||||||
|
class UnauthorizedError(CustomException):
|
||||||
|
def __init__(self, detail="Unauthorized access"):
|
||||||
|
super().__init__(detail, 401)
|
||||||
|
|
||||||
|
|
||||||
|
class ForbiddenError(CustomException):
|
||||||
|
def __init__(self, detail="Forbidden"):
|
||||||
|
super().__init__(detail, 403)
|
||||||
|
|
||||||
|
|
||||||
|
class APIKeyError(CustomException):
|
||||||
|
def __init__(self, detail="API key error"):
|
||||||
|
super().__init__(detail, 401)
|
||||||
|
|
||||||
|
|
||||||
|
class FilterError(CustomException):
|
||||||
|
def __init__(self, detail="Filter error"):
|
||||||
|
super().__init__(detail, 400)
|
||||||
|
|
@ -4,9 +4,8 @@ from uuid import UUID
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from httpx import HTTPError, HTTPStatusError
|
from httpx import HTTPError, HTTPStatusError
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from langflow.services.base import Service
|
from langflow.services.base import Service
|
||||||
|
from langflow.services.store.exceptions import APIKeyError, FilterError, ForbiddenError
|
||||||
from langflow.services.store.schema import (
|
from langflow.services.store.schema import (
|
||||||
CreateComponentResponse,
|
CreateComponentResponse,
|
||||||
DownloadComponentResponse,
|
DownloadComponentResponse,
|
||||||
|
|
@ -19,6 +18,7 @@ from langflow.services.store.utils import (
|
||||||
process_tags_for_post,
|
process_tags_for_post,
|
||||||
update_components_with_user_data,
|
update_components_with_user_data,
|
||||||
)
|
)
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from langflow.services.settings.service import SettingsService
|
from langflow.services.settings.service import SettingsService
|
||||||
|
|
@ -196,7 +196,7 @@ class StoreService(Service):
|
||||||
liked_filter = self.build_liked_filter()
|
liked_filter = self.build_liked_filter()
|
||||||
filter_conditions.append(liked_filter)
|
filter_conditions.append(liked_filter)
|
||||||
elif liked and not store_api_Key:
|
elif liked and not store_api_Key:
|
||||||
raise ValueError("You must provide an API key to filter by likes")
|
raise APIKeyError("You must provide an API key to filter by likes")
|
||||||
|
|
||||||
if filter_by_user and store_api_Key:
|
if filter_by_user and store_api_Key:
|
||||||
user_data = user_data_var.get()
|
user_data = user_data_var.get()
|
||||||
|
|
@ -204,7 +204,7 @@ class StoreService(Service):
|
||||||
raise ValueError("No user data")
|
raise ValueError("No user data")
|
||||||
filter_conditions.append({"user_created": {"_eq": user_data["id"]}})
|
filter_conditions.append({"user_created": {"_eq": user_data["id"]}})
|
||||||
elif filter_by_user and not store_api_Key:
|
elif filter_by_user and not store_api_Key:
|
||||||
raise ValueError("You must provide an API key to filter your components")
|
raise APIKeyError("You must provide an API key to filter your components")
|
||||||
else:
|
else:
|
||||||
filter_conditions.append({"status": {"_in": ["public", "Public"]}})
|
filter_conditions.append({"status": {"_in": ["public", "Public"]}})
|
||||||
|
|
||||||
|
|
@ -256,7 +256,7 @@ class StoreService(Service):
|
||||||
|
|
||||||
return results_objects, metadata
|
return results_objects, metadata
|
||||||
|
|
||||||
async def get_liked_by_user_components(self, component_ids: List[UUID], api_key: str) -> List[str]:
|
async def get_liked_by_user_components(self, component_ids: List[str], api_key: str) -> List[str]:
|
||||||
# Get fields id
|
# Get fields id
|
||||||
# filter should be "id is in component_ids AND liked_by directus_users_id token is api_key"
|
# filter should be "id is in component_ids AND liked_by directus_users_id token is api_key"
|
||||||
# return the ids
|
# return the ids
|
||||||
|
|
@ -339,7 +339,7 @@ class StoreService(Service):
|
||||||
try:
|
try:
|
||||||
errors = response.json()
|
errors = response.json()
|
||||||
message = errors["errors"][0]["message"]
|
message = errors["errors"][0]["message"]
|
||||||
raise ValueError(message)
|
raise FilterError(message)
|
||||||
except UnboundLocalError:
|
except UnboundLocalError:
|
||||||
pass
|
pass
|
||||||
raise ValueError(f"Upload failed: {exc}")
|
raise ValueError(f"Upload failed: {exc}")
|
||||||
|
|
@ -447,9 +447,9 @@ class StoreService(Service):
|
||||||
comp_count = metadata.get("filter_count", 0)
|
comp_count = metadata.get("filter_count", 0)
|
||||||
except HTTPStatusError as exc:
|
except HTTPStatusError as exc:
|
||||||
if exc.response.status_code == 403:
|
if exc.response.status_code == 403:
|
||||||
raise ValueError("You are not authorized to access this public resource")
|
raise ForbiddenError("You are not authorized to access this public resource")
|
||||||
elif exc.response.status_code == 401:
|
elif exc.response.status_code == 401:
|
||||||
raise ValueError("You are not authorized to access this resource. Please check your API key.")
|
raise APIKeyError("You are not authorized to access this resource. Please check your API key.")
|
||||||
try:
|
try:
|
||||||
if result and not metadata:
|
if result and not metadata:
|
||||||
if len(result) >= limit:
|
if len(result) >= limit:
|
||||||
|
|
@ -464,9 +464,9 @@ class StoreService(Service):
|
||||||
comp_count = 0
|
comp_count = 0
|
||||||
except HTTPStatusError as exc:
|
except HTTPStatusError as exc:
|
||||||
if exc.response.status_code == 403:
|
if exc.response.status_code == 403:
|
||||||
raise ValueError("You are not authorized to access this public resource")
|
raise ForbiddenError("You are not authorized to access this public resource")
|
||||||
elif exc.response.status_code == 401:
|
elif exc.response.status_code == 401:
|
||||||
raise ValueError("You are not authorized to access this resource. Please check your API key.")
|
raise APIKeyError("You are not authorized to access this resource. Please check your API key.")
|
||||||
|
|
||||||
if store_api_Key:
|
if store_api_Key:
|
||||||
# Now, from the result, we need to get the components
|
# Now, from the result, we need to get the components
|
||||||
|
|
@ -482,5 +482,5 @@ class StoreService(Service):
|
||||||
# If we get an error here, it means the user is not authorized
|
# If we get an error here, it means the user is not authorized
|
||||||
authorized = False
|
authorized = False
|
||||||
else:
|
else:
|
||||||
authorized = True
|
authorized = await self.check_api_key(store_api_Key)
|
||||||
return ListComponentResponseModel(results=result, authorized=authorized, count=comp_count)
|
return ListComponentResponseModel(results=result, authorized=authorized, count=comp_count)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue