Skip to main content

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 Public re-exports of the most common symbols
approck_fastapi_utils.auth ensure_current_user, optional_current_user, ensure_current_superuser, JwtPayload
approck_fastapi_utils.jwt encode_payload, decode_payload, get_token_from_header
approck_fastapi_utils.exceptions CustomException hierarchy with HTTP status codes
approck_fastapi_utils.exception_handlers Handlers and register_exception_handlers(profile=...)
approck_fastapi_utils.responses JSON responses and OpenAPI schema helpers
approck_fastapi_utils.response Prebuilt 404 response schema
approck_fastapi_utils.types CommaSeparatedList for query parameters
approck_fastapi_utils.testing JWT/auth helpers for pytest
approck_fastapi_utils.gateway build_gateway_headers for proxy routes
approck_fastapi_utils.sqlalchemy.exception_handlers Handlers for DBAPIError and NoResultFound (requires the sqlalchemy extra)

Usage

Register exception handlers

Use a preset instead of wiring handlers manually:

from fastapi import FastAPI

from approck_fastapi_utils import register_exception_handlers

app = FastAPI()
register_exception_handlers(app, profile="api")

Profiles:

Profile Handlers
minimal HTTPException, CustomException
api minimal + RequestValidationError, NoResultFound
internal api + DBAPIError (with optional database_sanitize=True)

CustomException and HTTP status codes

Built-in exceptions map to HTTP codes automatically. Subclasses can set status_code on the class or pass it to __init__:

from approck_fastapi_utils import Conflict, CustomException, NotFound

class OrderAlreadyPaid(CustomException):
    status_code = 409

raise Conflict("already exists")          # -> 409
raise NotFound("missing")                   # -> 404
raise CustomException("bad", status_code=418)

Error body contract: {"successful": false, "code": "...", "detail": "..."}.

JWT payload header

ensure_current_user reads X-JWT-Payload (URL-safe base64 JSON). Invalid payloads raise Unauthorized (401).

from fastapi import APIRouter, Depends

from approck_fastapi_utils import ensure_current_user, optional_current_user
from approck_fastapi_utils.responses import SuccessfulResponse

router = APIRouter()

@router.get("/me")
async def read_me(payload: dict = Depends(ensure_current_user)):
    return SuccessfulResponse()

@router.get("/public")
async def public(payload: dict | None = Depends(optional_current_user())):
    ...

JWT encode/decode

from approck_fastapi_utils import decode_payload, encode_payload

payload = {"user_id": 1, "is_superuser": False}
encoded = encode_payload(payload)
claims = decode_payload(encoded)  # returns None on invalid input

Testing helpers

from approck_fastapi_utils.testing import auth_headers, override_current_user

headers = auth_headers(user_id=42, is_superuser=True)
override_current_user(app, user_id=42)

Standard JSON responses and OpenAPI examples

from approck_fastapi_utils import HTTP_404_NOT_FOUND, SuccessfulResponse, custom_exception_response_schema, error_response_schema
from approck_fastapi_utils.exceptions import NotFound

@router.get(
    "/health",
    responses={
        **SuccessfulResponse.schema(),
        **error_response_schema(400, "Bad request"),
        **custom_exception_response_schema(NotFound),
        **HTTP_404_NOT_FOUND,
    },
)
async def health():
    return SuccessfulResponse()

Comma-separated query lists

CommaSeparatedList[T] accepts ?ids=1,2,3. Whitespace is trimmed, empty string yields [].

from typing import Annotated

from fastapi import Query

from approck_fastapi_utils import CommaSeparatedList

ids: Annotated[CommaSeparatedList[int], Query(description="Example: 1,2,3")]

Gateway/proxy headers

from approck_fastapi_utils import build_gateway_headers

headers = build_gateway_headers(
    authorization=request.headers.get("Authorization"),
    x_jwt_payload=request.headers.get("X-JWT-Payload"),
)

Breaking changes in 0.2.0

  • Invalid X-JWT-Payload in ensure_current_user now raises Unauthorized (401) instead of Forbidden (403).
  • decode_payload returns None instead of raising on invalid input.
  • Header alias is explicitly X-JWT-Payload.

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

approck_fastapi_utils-0.2.0.tar.gz (9.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

approck_fastapi_utils-0.2.0-py3-none-any.whl (13.3 kB view details)

Uploaded Python 3

File details

Details for the file approck_fastapi_utils-0.2.0.tar.gz.

File metadata

  • Download URL: approck_fastapi_utils-0.2.0.tar.gz
  • Upload date:
  • Size: 9.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","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

Hashes for approck_fastapi_utils-0.2.0.tar.gz
Algorithm Hash digest
SHA256 712ab9436ac83b5c42f0860d7bdabd7c3b91505c56c1978c0e3d2fac8900d885
MD5 7de54f7d649b695081ad92b3c94f33f6
BLAKE2b-256 6d089055dab271e7bd54c1c88f73e6115dcbb94ae1e62ac52259dc62f109dec2

See more details on using hashes here.

File details

Details for the file approck_fastapi_utils-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: approck_fastapi_utils-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 13.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","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

Hashes for approck_fastapi_utils-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8ce6d9b720cdae68ece6db084bab52f36ee0ffb2ec8b32d63a97ff0146bc4905
MD5 836121b01a7fd02b3d906b6bb3539eb0
BLAKE2b-256 4c6873fe1615c888f6ac84566225735131d34f5595bbc1695023fd1650293888

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page