Skip to content

Standardize API errors and structured logging - #53

Merged
AlexKitipov merged 1 commit into
mainfrom
codex/add-structured-error-handling-and-logging
Jun 9, 2026
Merged

Standardize API errors and structured logging#53
AlexKitipov merged 1 commit into
mainfrom
codex/add-structured-error-handling-and-logging

Conversation

@AlexKitipov

Copy link
Copy Markdown
Owner

Motivation

  • Make client-facing errors predictable and machine-readable by standardizing the error response shape and preserving application error codes.
  • Improve operational observability by emitting structured JSON logs to stdout and adding per-request logging so deployments can reliably collect logs.

Description

  • Add an AppException exception handler that preserves error_code and returns the new standardized response shape via a shared helper _error_response in app/main.py.
  • Add handlers for request validation errors (RequestValidationError), FastAPI HTTPException, and a global catch-all that all return the standardized JSON error object and log appropriate structured events.
  • Implement structured JSON logging and request lifecycle logging in app/middleware/logging.py, defaulting to stdout and only attaching a file handler when log_file is explicitly provided.
  • Wire up the structured logger and RequestLoggingMiddleware in app/main.py and clarify AppException's doc/annotations in app/utils/exceptions.py.
  • Update tests to expect the new error shape and add tests for preserved app error codes and JSON stdout logging in tests/test_app_smoke.py, and update redirect/upgrade tests in tests/test_redirect.py and tests/test_users_upgrade.py accordingly.

Testing

  • Ran pytest -q; all tests passed.
  • Ran linting via python -m flake8 app/main.py app/middleware/logging.py app/utils/exceptions.py tests/test_app_smoke.py tests/test_redirect.py tests/test_users_upgrade.py; checks passed.
  • Formatting tools (black, isort) were applied to updated files during the rollout.

Codex Task

@AlexKitipov
AlexKitipov merged commit 159474c into main Jun 9, 2026
2 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 98f0a2e8a3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/main.py
Comment on lines +118 to +122
return _error_response(
status_code=exc.status_code,
error_code=f"HTTP_{exc.status_code}",
message=str(exc.detail),
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve WWW-Authenticate on auth failures

When protected endpoints raise HTTPException(..., headers={"WWW-Authenticate": "Bearer"}) from app/security.py or app/dependencies.py, this new handler rebuilds the response without passing through exc.headers. For example, an invalid bearer token on /api/v1/users/stats now returns a 401 with no WWW-Authenticate challenge, which breaks clients that rely on the header to recognize bearer-auth failures; include the original headers when creating the standardized response.

Useful? React with 👍 / 👎.

Comment thread app/main.py
Comment on lines +106 to +107
@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle Starlette HTTP exceptions too

Registering the handler only for FastAPI's HTTPException leaves framework-generated errors in the old shape because routing errors such as 404/405 are raised as starlette.exceptions.HTTPException. I checked an unknown route and it still returns {"detail":"Not Found"} instead of the standardized success/error envelope, so clients still see inconsistent error formats for missing paths or unsupported methods unless the handler is registered for Starlette's exception class as well.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant