From 5d91c059259b8ec3de5db5f08848396f111fbb3d Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Thu, 29 Jan 2026 18:18:04 -0500 Subject: [PATCH] feat(api): standardize V3 error status codes and documentation - Updated V3 CRUD routers to return 400 Bad Request for database schema errors (unknown columns) across all list and search endpoints. - Fixed serialization issue in nested patch endpoint. - Overhauled Section 7 of Frontend Integration Guide to document HTTP status code mappings for common error categories. --- app/routers/api_crud_v3.py | 9 +++++++++ app/routers/api_crud_v3_nested.py | 2 +- documentation/GUIDE__V3_FRONTEND_API.md | 17 ++++++++++++----- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/app/routers/api_crud_v3.py b/app/routers/api_crud_v3.py index 13e4edd..c0b0ed4 100644 --- a/app/routers/api_crud_v3.py +++ b/app/routers/api_crud_v3.py @@ -262,6 +262,15 @@ async def get_obj_li( as_list=True, ) + if sql_result is False: + # Standardized rich error bubbling + db_err = format_db_error(get_last_sql_error()) + + # If it's a schema error (like Unknown Column), it's a 400 Bad Request + status_code = 400 if db_err.category == "database_schema" else 500 + + return mk_resp(data=False, status_code=status_code, response=response, status_message="Listing failed due to database error.", details=db_err.dict()) + if sql_result: resp_data_li = [base_name(**record).dict(by_alias=serialization.by_alias, exclude_unset=serialization.exclude_unset, exclude_defaults=serialization.exclude_defaults, exclude_none=serialization.exclude_none) for record in sql_result] return mk_resp(data=resp_data_li, response=response) diff --git a/app/routers/api_crud_v3_nested.py b/app/routers/api_crud_v3_nested.py index b76a058..51d7252 100644 --- a/app/routers/api_crud_v3_nested.py +++ b/app/routers/api_crud_v3_nested.py @@ -310,7 +310,7 @@ async def patch_child_obj( return mk_resp(data=True, response=response, status_message="Updated successfully.") else: db_err = format_db_error(get_last_sql_error()) - return mk_resp(data=False, status_code=400, response=response, status_message="Update failed.", details=db_err) + return mk_resp(data=False, status_code=400, response=response, status_message="Update failed.", details=db_err.dict()) @router.delete('/{parent_obj_type}/{parent_obj_id}/{child_obj_type}/{child_obj_id}', response_model=Resp_Body_Base) diff --git a/documentation/GUIDE__V3_FRONTEND_API.md b/documentation/GUIDE__V3_FRONTEND_API.md index 1be6062..c6ba886 100644 --- a/documentation/GUIDE__V3_FRONTEND_API.md +++ b/documentation/GUIDE__V3_FRONTEND_API.md @@ -132,11 +132,18 @@ V3 uses a **String-Only ID Vision**. The frontend NEVER handles or stores databa V3 returns machine-readable error objects in `meta.details` for failures. -**Common Categories:** -- `database_duplicate`: Non-unique value (Code 1062). -- `database_constraint`: Foreign key violation (Codes 1451, 1452). -- `database_schema`: Invalid column name (Codes 1054, 1146). -- `validation`: Pydantic validation failed (Check `details` for field-specific errors). +### HTTP Status Codes +- **`400 Bad Request`**: Used for client-driven errors including invalid search fields, validation failures, and constraint violations. +- **`403 Forbidden`**: Missing or invalid API Key / Account Context. +- **`404 Not Found`**: Object ID does not exist. +- **`500 Internal Server Error`**: Unexpected server crash or database connection failure. + +### Common Error Categories +Found in `meta.details.category`: +- `database_duplicate`: Non-unique value (Code 1062). -> **400** +- `database_constraint`: Foreign key violation (Codes 1451, 1452). -> **400** +- `database_schema`: Invalid column name or missing field in the requested `view` (Codes 1054, 1146). -> **400** +- `validation`: Pydantic validation failed (Check `details` for field-specific errors). -> **400** ---