Skip to main content

Idempotency middleware for Django REST Framework

Project description

drf-idem

Читать на русском (Read in Russian)

Idempotency middleware for Django REST Framework. Prevents duplicate request processing using Redis.

When a client sends the same request twice (network retry, double-click, bug), drf-idem detects the duplicate and returns an immediate response — without running your business logic a second time.

Installation

# In a uv-managed project
uv add drf-idem

# Or via pip
pip install drf-idem

Quick Start

1. Add to INSTALLED_APPS:

INSTALLED_APPS = [
    ...
    "drf_idem",
]

2. Add middleware first in the list:

MIDDLEWARE = [
    "drf_idem.middleware.IdempotencyMiddleware",
    ...
]

3. Configure a dedicated Redis cache backend:

CACHES = {
    "default": { ... },
    "drf_idem": {
        "BACKEND": "django.core.cache.backends.redis.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/2",
    },
}

4. Add settings:

DRF_IDEM = {
    "HEADER": "HTTP_X_REQUEST_ID",   # reads X-Request-ID header
    "TTL": 60,                        # seconds, max 60
    "CACHE_BACKEND": "drf_idem",
    "ENDPOINTS": [],                  # empty = check all endpoints
                                      # formats: "POST /path", "/path" (all METHODS), "* /path" (absolutely all)
    "METHODS": ["POST", "PUT", "PATCH", "DELETE"],
}

5. Mount admin stats page in urls.py:

# IMPORTANT: place before path("admin/", admin.site.urls)
urlpatterns = [
    path("admin/drf-idem/", include("drf_idem.urls")),
    path("admin/", admin.site.urls),
    ...
]

Open /admin/drf-idem/stats/ to see duplicate request statistics.

How It Works

The client attaches a unique X-Request-ID header to each request:

POST /api/payments/ HTTP/1.1
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json

{"amount": 100}

First request — processed normally, key stored in Redis with TTL.

Duplicate request (same X-Request-ID + same method + same path, within TTL):

HTTP/1.1 200 OK
Content-Type: application/json

{"amount": 100}

Business logic is not executed. The exact same HTTP status and body from the original response are returned transparently to the client.

Settings Reference

Key Default Description
HEADER HTTP_X_REQUEST_ID Django META key for the idempotency header (X-Request-IDHTTP_X_REQUEST_ID)
TTL 60 Seconds to remember a request. Capped at 60.
CACHE_BACKEND "drf_idem" Django CACHES alias to use
ENDPOINTS [] Endpoint filter (empty = apply to all). Formats: "METHOD /path", "/path", "* /path"
METHODS ["POST", "PUT", "PATCH", "DELETE"] HTTP methods to check when ENDPOINTS is empty
STATS_TTL 604800 (7 days) TTL for statistics data in Redis

Endpoint Filtering

Use ENDPOINTS to restrict which endpoints are protected:

DRF_IDEM = {
    "ENDPOINTS": [
        "POST /api/payments/",   # only POST to /api/payments/*
        "/api/orders/",          # any method from METHODS to /api/orders/*
        "* /api/critical/",      # all methods to /api/critical/*
    ],
}

Pattern formats:

  • "METHOD /path/prefix" — specific method + path prefix
  • "/path/prefix" — any method from METHODS + path prefix
  • "* /path/prefix" — all methods + path prefix

When ENDPOINTS is empty, all endpoints matching METHODS are checked.

Security

  • Key isolation: Cache keys use SHA-256 of (method, path, request_id) — no injection via separator characters.
  • Input validation: request_id must be ≤ 128 chars and match [A-Za-z0-9\-_./]+. Invalid values return HTTP 400.
  • Atomic writes: Uses cache.add() (Redis SETNX) to eliminate TOCTOU race conditions.
  • Admin protection: Stats page requires is_staff=True.

Admin Statistics

The stats page at /admin/drf-idem/stats/ shows:

  • Top endpoints by duplicate count
  • Timestamp of last duplicate
  • Total Redis memory used by drf_idem:* keys (with warning if > 10 MB)

Development

git clone https://github.com/example/drf-idem
cd drf-idem
uv sync --extra dev
uv run pytest -v

License

MIT

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

drf_idem-0.1.0.tar.gz (12.5 kB view details)

Uploaded Source

Built Distribution

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

drf_idem-0.1.0-py3-none-any.whl (10.2 kB view details)

Uploaded Python 3

File details

Details for the file drf_idem-0.1.0.tar.gz.

File metadata

  • Download URL: drf_idem-0.1.0.tar.gz
  • Upload date:
  • Size: 12.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for drf_idem-0.1.0.tar.gz
Algorithm Hash digest
SHA256 06fd2faddcac1195bbee01b93aafc36f0e139c019aea5a6a95e17cb62aecf748
MD5 5d3ab3e75ef1f72bb8a9dfbcfa727d1f
BLAKE2b-256 f0e98a33d58c8e0caab68d65d6017d49fdba1c6f28d27cba4bca1c99d9d586f2

See more details on using hashes here.

Provenance

The following attestation bundles were made for drf_idem-0.1.0.tar.gz:

Publisher: publish.yml on safonin/drf-idem

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file drf_idem-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: drf_idem-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for drf_idem-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0eb354da79b62b37181f7b0628c5afd00a8ab5fb68488c100a1a400db0b28c21
MD5 c810cf9af17cf1c63b2a2e415b9efda2
BLAKE2b-256 08902c15f78e47a59aec1a625c0167c0fe87d53718838755845d53dadcd07ef0

See more details on using hashes here.

Provenance

The following attestation bundles were made for drf_idem-0.1.0-py3-none-any.whl:

Publisher: publish.yml on safonin/drf-idem

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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