Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ jobs:
- name: Build release distributions
run: |
# NOTE: put your own distribution build steps here.
python -m pip install build
python -m build
python -m pip install uv
uv build

- name: Upload distributions
uses: actions/upload-artifact@v4
Expand Down
File renamed without changes.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ The above code demonstrates how to handle exceptions in FastAPI using the `APIEx
When you run your FastAPI app and open **Swagger UI** (`/docs`),
your endpoints will display **clean, predictable response schemas** like this below:

![_user_{user_id}.gif](/assets/apiexception-indexBasicUsage-1.gif)
![_user_{user_id}.gif](/docs/assets/apiexception-indexBasicUsage-1.gif)

---

Expand Down Expand Up @@ -244,10 +244,12 @@ What if you forget to handle an exception such as in the **example** above?
```python
from api_exception import APIException, ExceptionCode, register_exception_handlers
from fastapi import FastAPI

app = FastAPI()

register_exception_handlers(app)


@app.get("/login")
async def login(username: str, password: str):
if username != "admin" or password != "admin":
Expand All @@ -265,10 +267,12 @@ async def login(username: str, password: str):
```python
from api_exception import ResponseModel, register_exception_handlers
from fastapi import FastAPI

app = FastAPI()

register_exception_handlers(app)


@app.get("/success")
async def success():
return ResponseModel(
Expand All @@ -279,7 +283,7 @@ async def success():

**_Response Model In Abstract:_**

![apiexception-responseModel.gif](assets/apiexception-responseModel.gif)
![apiexception-responseModel.gif](docs/assets/apiexception-responseModel.gif)


---
Expand All @@ -291,6 +295,7 @@ Always extend BaseExceptionCode — don’t subclass ExceptionCode directly!
```python
from api_exception import BaseExceptionCode


class CustomExceptionCode(BaseExceptionCode):
USER_NOT_FOUND = ("-404", "User not found.", "User does not exist.")
INVALID_API_KEY = ("API-401", "Invalid API key.", "Key missing or invalid.")
Expand Down Expand Up @@ -323,6 +328,7 @@ set_default_http_codes({
---

## 🌐 Multiple Apps Support

```python
from fastapi import FastAPI
from api_exception import register_exception_handlers
Expand Down Expand Up @@ -385,6 +391,7 @@ This example serves as a **one-stop reference** to see how `api_exception` can b
import unittest
from api_exception import APIException, ExceptionCode, ResponseModel


class TestAPIException(unittest.TestCase):
def test_api_exception(self):
exc = APIException(error_code=ExceptionCode.AUTH_LOGIN_FAILED)
Expand All @@ -394,6 +401,7 @@ class TestAPIException(unittest.TestCase):
res = ResponseModel(data={"foo": "bar"})
self.assertEqual(res.status.value, "SUCCESS")


if __name__ == "__main__":
unittest.main()
```
Expand Down
Binary file removed assets/logo.png
Binary file not shown.
Binary file removed assets/pip-install-APIException.gif
Binary file not shown.
Binary file removed assets/pip-install-apiexception-1.gif
Binary file not shown.
Empty file removed custom_enum/__init__.py
Empty file.
12 changes: 8 additions & 4 deletions docs/advanced/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ they’re also **automatically logged** in a clean, structured way.
## ✅ How It Works

**Auto-logging:**

```python
from api_exception import register_exception_handlers
from fastapi import FastAPI
Expand Down Expand Up @@ -48,6 +49,7 @@ Here’s a quick guide:

```python
from api_exception import logger

logger.setLevel("DEBUG")
```

Expand Down Expand Up @@ -88,6 +90,7 @@ from fastapi import FastAPI, Request

app = FastAPI()


def my_extra_fields(request: Request, exc: Exception):
def mask(value: str, visible: int = 4) -> str:
"""Mask sensitive data (keep last `visible` chars)."""
Expand All @@ -106,6 +109,7 @@ def my_extra_fields(request: Request, exc: Exception):
"api_key": mask(request.query_params.get("api_key", "")),
}


register_exception_handlers(app, extra_log_fields=my_extra_fields)
```

Expand Down Expand Up @@ -138,10 +142,10 @@ authorization=********abcd api_key=*****f9d2
```python
from api_exception import logger

logger.debug("Debugging details: user_id=42, payload=...")
logger.info("Service started successfully on port 8000")
logger.warning("Slow query detected, taking longer than 2s")
logger.error("Failed to connect to Redis")
logger.debug("Debugging details: user_id=42, payload=...")
logger.info("Service started successfully on port 8000")
logger.warning("Slow query detected, taking longer than 2s")
logger.error("Failed to connect to Redis")
logger.critical("Database unreachable! Shutting down...")
```

Expand Down
4 changes: 3 additions & 1 deletion docs/advanced/rfc7807.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@ from fastapi import FastAPI

app = FastAPI()
register_exception_handlers(
app,
app,
response_format=ResponseFormat.RFC7807
)
```

This will return error responses with the application/problem+json content type, formatted according to the RFC 7807 spec.

### 🧪 RFC7807 Usage Example

```python
from api_exception import APIException, APIResponse
from api_exception import ResponseFormat
Expand All @@ -47,6 +48,7 @@ from .exceptions import CustomExceptionCode
app = FastAPI()
register_exception_handlers(app, response_format=ResponseFormat.RFC7807)


@app.get(
"/rfc7807",
response_model=ResponseModel[UserResponse],
Expand Down
Loading