Small helpers for FastAPI: JWT header auth, JSON responses, exception handlers, and Pydantic query types.
Project description
approck-fastapi-utils
Small utilities for FastAPI services: JWT payload decoding from headers, standardized JSON responses, reusable exception handlers, a Pydantic-friendly comma-separated list type, and optional SQLAlchemy error handlers.
Python: 3.10+
Install
From PyPI:
uv add approck-fastapi-utils
Or with pip:
pip install approck-fastapi-utils
Optional SQLAlchemy handlers:
uv add "approck-fastapi-utils[sqlalchemy]"
What is included
| Module | Purpose |
|---|---|
approck_fastapi_utils.auth |
ensure_current_user dependency: reads X-Jwt-Payload, decodes base64 JSON, raises Forbidden if invalid |
approck_fastapi_utils.jwt |
get_token_from_header, decode_payload |
approck_fastapi_utils.exceptions |
Unauthorized, Forbidden, NotFound, CustomException |
approck_fastapi_utils.exception_handlers |
Handlers for HTTPException and custom exceptions |
approck_fastapi_utils.responses |
SuccessfulResponse, FailedResponse, OpenAPI-friendly ResponseSchema |
approck_fastapi_utils.response |
Prebuilt 404 response schema |
approck_fastapi_utils.types |
CommaSeparatedList for query parameters |
approck_fastapi_utils.sqlalchemy.exception_handlers |
Handlers for DBAPIError and NoResultFound (requires the sqlalchemy extra) |
Usage
Register exception handlers
Wire handlers once on the FastAPI app so HTTPException and library exceptions share the same JSON shape (successful, detail, and code for custom types).
from fastapi import FastAPI, HTTPException
from approck_fastapi_utils.exception_handlers import custom_exception_handler, http_exception_handler
from approck_fastapi_utils.exceptions import CustomException
app = FastAPI()
app.add_exception_handler(HTTPException, http_exception_handler)
app.add_exception_handler(CustomException, custom_exception_handler)
CustomException in one breath
Raise domain errors like normal Python exceptions — the client always gets the same JSON: successful: false, code = your class name (great for UI/tests), detail = message. Built-ins map to HTTP for free: Unauthorized 401, Forbidden 403, NotFound 404; your own subclasses default to 400 unless you add a dedicated handler.
from approck_fastapi_utils.exceptions import CustomException, NotFound
class OrderAlreadyPaid(CustomException):
pass
raise OrderAlreadyPaid("already paid") # -> 400 + code "OrderAlreadyPaid"
raise NotFound("missing") # -> 404 + code "NotFound"
With the optional SQLAlchemy extra, register database errors the same way:
from sqlalchemy.exc import DBAPIError, NoResultFound
from approck_fastapi_utils.sqlalchemy.exception_handlers import database_error_handler, database_not_found_handler
app.add_exception_handler(DBAPIError, database_error_handler)
app.add_exception_handler(NoResultFound, database_not_found_handler)
JWT payload header (ensure_current_user)
ensure_current_user expects a header X-Jwt-Payload whose value is URL-safe base64-encoded JSON (for example the same JSON you would put in a JWT payload, without the signature segment). The dependency returns the decoded dict or raises Forbidden.
from fastapi import APIRouter, Depends
from approck_fastapi_utils.auth import ensure_current_user
from approck_fastapi_utils.responses import SuccessfulResponse
router = APIRouter()
@router.get("/me")
async def read_me(payload: dict = Depends(ensure_current_user)):
# use payload (e.g. "sub", roles) in your logic
return SuccessfulResponse()
Manual JWT helpers
Useful if you build another header scheme but still want the same parsing helpers.
from approck_fastapi_utils.jwt import decode_payload, get_token_from_header
token = get_token_from_header(authorization) # "Bearer <jwt>" -> "<jwt>"
claims = decode_payload(base64_payload_string) # base64url JSON -> dict
Standard JSON responses and OpenAPI examples
SuccessfulResponse / FailedResponse return {"successful": true|false}. Their .schema() helpers merge into route responses for OpenAPI; HTTP_404_NOT_FOUND is a ready-made 404 entry.
from fastapi import APIRouter
from approck_fastapi_utils.response import HTTP_404_NOT_FOUND
from approck_fastapi_utils.responses import FailedResponse, SuccessfulResponse
router = APIRouter()
@router.get(
"/health",
responses={**SuccessfulResponse.schema(), **FailedResponse.schema(), **HTTP_404_NOT_FOUND},
)
async def health():
return SuccessfulResponse()
Comma-separated query lists
CommaSeparatedList[T] accepts a single comma-separated string (e.g. ?ids=1,2,3) or repeated query values and validates elements as T.
from typing import Annotated
from fastapi import APIRouter, Query
from approck_fastapi_utils.types import CommaSeparatedList
router = APIRouter()
@router.get("/items")
async def list_items(
ids: Annotated[CommaSeparatedList[int], Query(description="Example: 1,2,3")],
):
return {"ids": list(ids)}
Development
This repository uses uv.
uv sync --group dev --extra sqlalchemy
uv run ruff check .
uv run ruff format --check .
uv run mypy approck_fastapi_utils
uv run pytest
License
MIT — see LICENSE.
Contributing
Issues and pull requests are welcome. Please run the checks above before submitting a change.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file approck_fastapi_utils-0.1.11.tar.gz.
File metadata
- Download URL: approck_fastapi_utils-0.1.11.tar.gz
- Upload date:
- Size: 6.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f734e001e3d876af5cfcd1aca3aa1b95ad1569f7081805ffac972670da1672fd
|
|
| MD5 |
9017d58a44b74c9d0c744bd2678936fa
|
|
| BLAKE2b-256 |
b490f4cda4274d6675457931723f51ee1eed1a40592c8d64628ecdfe1650664a
|
File details
Details for the file approck_fastapi_utils-0.1.11-py3-none-any.whl.
File metadata
- Download URL: approck_fastapi_utils-0.1.11-py3-none-any.whl
- Upload date:
- Size: 9.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
25e76f7ccced37f24672dea6cbed854976140ec0d66cc58d1bf7914be9e3a367
|
|
| MD5 |
47115eb99c44eca0faf4297d2cfb3169
|
|
| BLAKE2b-256 |
d4eff2a9385dbe26be1d5eae6b9729402c304c782cc6a013f193f2df0866f3ad
|