Skip to content

Commit d007e47

Browse files
committed
Release v0.2.0
### Added - **Advanced logging customizations** in `register_exception_handlers`: - `log_level`: override verbosity for exception logging. - `log_request_context`: toggle to include/exclude request headers in logs. - `log_header_keys`: define which headers are logged (default: `x-request-id`, `user-agent`, etc.). - `extra_log_fields`: inject custom structured metadata into logs (e.g. `user_id`, masked API keys). - **Response headers echo** in `register_exception_handlers`: - `response_headers=True` → default headers echoed back. - `response_headers=False` → no headers echoed. - `response_headers=("x-user-id",)` → custom headers echoed. - `APIException` now accepts header parameters (headers can carry custom values into responses). - **Mypy** support added for static type checking. - Improved documentation for `register_exception_handlers` with usage patterns, logging, and examples. ### Changed - Logging format has been revamped → now more structured, readable, and consistent. - Error logging now includes richer metadata: request path, method, client IP, HTTP version, etc. ### Fixed - Swagger/OpenAPI sometimes showed inconsistent error schemas when `data` was missing. - **File structure cleanup**: imports in `__init__.py` were fixed and simplified. The package is now easier to import and fully modular. - Fixed a type issue where `error_code` was not properly annotated as `BaseExceptionCode`.
1 parent 01f30e7 commit d007e47

File tree

18 files changed

+1088
-404
lines changed

18 files changed

+1088
-404
lines changed

README.md

Lines changed: 60 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
[![Downloads](https://pepy.tech/badge/apiexception)](https://pepy.tech/project/apiexception)
1111
[![Python Versions](https://img.shields.io/pypi/pyversions/apiexception.svg)](https://pypi.org/project/apiexception/)
1212
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
13-
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
13+
[![Ruff](https://img.shields.io/badge/linting-ruff-%23ea580c?logo=ruff&logoColor=white)](https://github.com/astral-sh/ruff)
14+
[![uv](https://img.shields.io/badge/packaging-uv-%234285F4?logo=python&logoColor=white)](https://github.com/astral-sh/uv)
15+
[![Poetry](https://img.shields.io/badge/dependencies-poetry-%2360A5FA?logo=poetry&logoColor=white)](https://python-poetry.org/)
16+
1417

1518
**APIException** is a robust, production-ready Python library for FastAPI that simplifies exception handling and ensures consistent, well-structured API responses. Designed for developers who want to eliminate boilerplate error handling and improve Swagger/OpenAPI documentation, APIException makes your FastAPI projects cleaner and easier to maintain.
1619

@@ -30,6 +33,21 @@ Reading the [full documentation](https://akutayural.github.io/APIException/) is
3033

3134
---
3235

36+
!!! important "New in v0.2.0"
37+
APIException **v0.2.0** introduces major improvements:
38+
- Advanced structured logging (`log_level`, `log_header_keys`, `extra_log_fields`)
39+
- Response headers echo (`response_headers`)
40+
- Type-safety improvements with `mypy`
41+
- APIException accepts `headers` param <br>
42+
- Cleaner import/export structure <br>
43+
- 📢 Featured in [**Python Weekly #710**](https://www.pythonweekly.com/p/python-weekly-issue-710-august-14-2025-3200567a10d37d87) 🎉
44+
45+
46+
👉 For full details and usage examples, see
47+
[**register_exception_handlers reference**](https://akutayural.github.io/APIException/usage/register_exception_handlers/)
48+
49+
---
50+
3351
## 📦 Installation via pip
3452

3553
```bash
@@ -59,22 +77,44 @@ logger.setLevel("INFO") # Set logging level if needed
5977
## 🔍 Example: Error Handling with Custom Codes
6078

6179
```python
62-
from typing import List
63-
from fastapi import FastAPI, Path
80+
from typing import List, Optional, Any, Dict
81+
from fastapi import FastAPI, Path, Request
6482
from pydantic import BaseModel, Field
6583
from api_exception import (
6684
APIException,
6785
BaseExceptionCode,
6886
ResponseModel,
6987
register_exception_handlers,
70-
APIResponse
88+
APIResponse,
89+
logger,
90+
ResponseFormat
7191
)
7292

93+
logger.setLevel("DEBUG")
7394
app = FastAPI()
7495

75-
# Register exception handlers globally to have the consistent
76-
# error handling and response structure
77-
register_exception_handlers(app=app)
96+
97+
def my_extra_fields(request: Request, exc: Optional[BaseException]) -> Dict[str, Any]:
98+
user_id = request.headers.get("x-user-id", "anonymous")
99+
return {
100+
"masked_user_id": f"user-{user_id[-2:]}",
101+
"service": "billing-service",
102+
"has_exc": exc is not None,
103+
"exc_type": type(exc).__name__ if exc else None,
104+
}
105+
106+
107+
register_exception_handlers(app,
108+
response_format=ResponseFormat.RESPONSE_MODEL,
109+
log_traceback=True,
110+
log_traceback_unhandled_exception=False,
111+
log_level=10,
112+
log=True,
113+
response_headers=("x-user-id",),
114+
log_request_context=True,
115+
log_header_keys=("x-user-id",),
116+
extra_log_fields=my_extra_fields
117+
)
78118

79119

80120
# Define your custom exception codes extending BaseExceptionCode
@@ -178,7 +218,7 @@ In both `error` and the `success` cases, the response structure is **consistent*
178218

179219
- In the example above, when the `user_id` is `1`, it raises an `APIException` with a custom `error_code`, the response is formatted according to the `ResponseModel` and it's logged **automatically** as shown below:
180220

181-
![apiexception-indexApiExceptionLog.png](docs/assets/apiexception-indexApiExceptionLog.png)
221+
![apiexception-indexApiExceptionLog.png](docs/advanced/exception_1.png)
182222

183223
---
184224

@@ -198,7 +238,7 @@ What if you forget to handle an exception such as in the **example** above?
198238
}
199239
```
200240

201-
![apiexception-indexApiExceptionLog.png](docs/assets/apiexception-indexZeroDivisionLog.png)
241+
![apiexception-indexApiExceptionLog.png](docs/advanced/exception_2.png)
202242

203243

204244
**2️⃣ Raise an Exception**
@@ -410,155 +450,9 @@ Benchmark scripts and raw Locust reports are available in the [benchmark](https:
410450

411451
## 📜 Changelog
412452

413-
##v0.1.21 - 2025-08-18**
414-
**Initial stable and suggested version**
415-
416-
417-
### Fixed
418-
- Added missing `import traceback` in `__init__.py`.
419-
This resolves a `NameError` when using `register_exception_handlers` with traceback logging enabled.
420-
421-
422-
**v0.1.20 - 2025-08-18**
423-
424-
#### Changed
425-
- Restructured `__init__.py` to use **relative imports** (`from .module import ...`) instead of absolute imports for cleaner packaging and IDE compatibility.
426-
- Unified all public exports under `__all__` so that consumers can simply `from api_exception import ...` without needing sub-module paths.
427-
428-
#### Fixed
429-
- Resolved IDE/PyCharm highlighting issues where imports appeared red even though they worked at runtime.
430-
- Improved import resolution when using the package in external projects by flattening top-level exports.
431-
432-
**v0.1.19 - 2025-08-18**
433-
434-
#### Added
435-
- Unified import interface: all core classes and functions can now be imported directly from `api_exception` (e.g. `from api_exception import ResponseModel, APIException`).
436-
- Cleaner `__init__.py` exports with `__all__`.
437-
438-
#### Changed
439-
- Internal imports refactored, simplified folder structure for `enums.py`, `response_model.py`, `rfc7807_model.py`.
440-
441-
#### Fixed
442-
- Example and README imports updated to use new unified style.
443-
444-
445-
**v0.1.18 - 2025-08-17**
446-
447-
#### Added
448-
- Global logging control (`set_global_log`) with `log` param in `register_exception_handlers`.
449-
- RFC7807 full support with `application/problem+json` responses.
450-
- Automatic injection of `data: null` in OpenAPI error examples.
451-
452-
#### Changed
453-
- Dependency pins relaxed (`>=` instead of strict `==`).
454-
- Docstrings and examples updated (`use_response_model``response_format`).
455-
- Unified error logging (no logs when `log=False`).
456-
457-
#### Fixed
458-
- Fallback middleware now returns HTTP 500 instead of 422 for unexpected errors.
459-
- Traceback scope bug fixed in handlers.
460-
461-
**v0.1.17 (2025-08-10)**
462-
463-
- `RFC 7807` standard support for consistent error responses (`application/problem+json`)
464-
465-
- OpenAPI (Swagger) schema consistency: nullable fields are now explicitly shown for better compatibility
466-
467-
- `Poetry` support has been added for dependency management
468-
469-
- `uv` support has been added.
470-
471-
- extra logger message param has been added to `APIException` for more detailed logging
472-
473-
- `log_traceback` and `log_traceback_unhandled_exception` parameters have been added to `register_exception_handlers()` for more control over logging behavior
474-
475-
- `log_exception` parameter has been added to `APIException` for more control over logging behavior
476-
477-
- `log_message` parameter has been added to `APIException` for more control over logging behavior
478-
479-
- Logging now uses `add_file_handler()` to write logs to a file
480-
481-
- Logging improvements: now includes exception arguments in logs for better debugging
482-
483-
- Documentation has been updated.
484-
485-
- Readme.md has been updated.
486-
487-
**v0.1.16 (2025-07-22)**
488-
489-
- setup.py has been updated.
490-
491-
- Project name has been updated. Instead of `APIException` we will use `apiexception` to comply with `PEP 625`.
453+
Currently, the most stable and suggested version is v0.2.0
492454

493-
- Documentation has been updated.
494-
495-
- Readme.md has been updated.
496-
497-
**v0.1.15 (2025-07-22)**
498-
499-
- setup.py has been updated.
500-
501-
- Project name has been updated. Instead of `APIException` we will use `apiexception` to comply with `PEP 625`.
502-
503-
- Documentation has been updated.
504-
505-
- Readme.md has been updated.
506-
507-
508-
**v0.1.14 (2025-07-22)**
509-
510-
- setup.py has been updated.
511-
512-
- Project name has been updated. Instead of `APIException` we will use `apiexception` to comply with PEP 625.
513-
514-
**v0.1.13 (2025-07-21)**
515-
516-
- /examples/fastapi_usage.py has been updated.
517-
518-
- 422 Pydantic error has been fixed in APIResponse.default()
519-
520-
- Documentation has been updated.
521-
522-
- Exception Args has been added to the logs.
523-
524-
- Readme has been updated. New gifs have been added.
525-
526-
527-
**v0.1.12 (2025-07-14)**
528-
529-
- /examples/fastapi_usage.py has been updated.
530-
531-
- 422 Pydantic error has been handled in register_handler
532-
533-
- Documentation has been added.
534-
535-
- `use_fallback_middleware` has been added.
536-
537-
**v0.1.11 (2025-07-13)**
538-
539-
- Added CLI entrypoint (api_exception-info)
540-
541-
- Stable test suite with FastAPI TestClient
542-
543-
- Multiple app support
544-
545-
- Raw dict or Pydantic output
546-
547-
- Automatic logging improvements
548-
549-
550-
**v0.1.0 (2025-06-25)**
551-
552-
553-
🚀 Prototype started!
554-
555-
- Project scaffolding
556-
557-
- `ResponseModel` has been added
558-
559-
- `APIException` has been added
560-
561-
- Defined base ideas for standardizing error handling
455+
👉 [See full changelog](https://akutayural.github.io/APIException/changelog/)
562456

563457
---
564458

@@ -582,3 +476,12 @@ https://pypi.org/project/apiexception/
582476

583477
💻 **Author Website**
584478
https://ahmetkutayural.dev
479+
480+
---
481+
482+
## 🌍 Community & Recognition
483+
484+
- 📢 Featured in [**Python Weekly #710**](https://www.pythonweekly.com/p/python-weekly-issue-710-august-14-2025-3200567a10d37d87) 🎉
485+
- 🔥 Ranked **#3** globally in [r/FastAPI](https://www.reddit.com/r/FastAPI/comments/1ma39rq/make_your_fastapi_responses_clean_consistent/) under the *pip package* flair.
486+
- ⭐ Gaining traction on GitHub with developers adopting it for real-world FastAPI projects.
487+
- 💬 Actively discussed and shared across the Python community.

0 commit comments

Comments
 (0)