I have an API using Django Rest Framework that I'd like to protect against duplicate POST
requests (in the spirit of Post Once Exactly (POE)). The specific scenario I'm trying to handle is:
There was some discussion about this on the mailing list but no code materialized. How are people solving this problem right now?
I solved this by adding support for an X-Idempotency-Key
http header which can be set by the client. I then check for non-idempotent requests using a custom permission class that checks if the idempotency key has been seen recently (in the cache):
class IsIdempotent(permissions.BasePermission):
message = 'Duplicate request detected.'
def has_permission(self, request, view):
if request.method != 'POST':
return True
ival = request.META.get('HTTP_X_IDEMPOTENCY_KEY')
if ival is None:
return True
ival = ival[:128]
key = 'idemp-{}-{}'.format(request.user.pk, ival)
is_idempotent = bool(cache.add(key, 'yes',
settings.IDEMPOTENCY_TIMEOUT))
if not is_idempotent:
logger.info(u'Duplicate request (non-idempotent): %s', key)
return is_idempotent
which I can add to my views like so:
class MyViewSet(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet):
permission_classes = [permissions.IsAuthenticated,
IsIdempotent]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With