Enabling HashIds
Serializer extensions also provides support for
HashIds. Publicly exposing
database IDs to your end users is often not a good idea, as it both reveals the
number of entries (e.g. customers, orders etc.) in your database, and makes
misuse of vulnerable endpoints a lot easier when a sequential key is used (e.g.
/customers/1/
). HashIds aim to solve both issues.
To enable HashIds, add the following to your REST_FRAMEWORK
settings:
# settings.py
REST_FRAMEWORK = dict(
SERIALIZER_EXTENSIONS=dict(
USE_HASH_IDS=True,
HASH_IDS_SOURCE='my_app.HASH_IDS'
)
)
# my_app/__init__.py
import hashids
HASH_IDS = hashids.Hashids(salt='MYSALT')
Expanded ID fields will now use HashIds:
# serializers.py
class OwnerSerializer(SerializerExtensionsMixin, ModelSerializer):
class Meta:
model = models.Owner
fields = ('name',)
expandable_fields = dict(
organization=OrganizationSerializer,
)
>>> GET /owners/xFj/
{
"name": "Tyrell",
"organization_id": "4Vd"
}
Django Generic Class-Based Views
The ExternalIdViewMixin
is provided to simplify retrieving objects when using
Rest Framework's
generic views.
Simply modify your views to apply the mixin:
# views.py
from rest_framework.generics import RetrieveAPIView
from rest_framework_serializer_extensions.views import (
ExternalIdViewMixin, SerializerExtensionsAPIViewMixin)
from app import models, serializers
class OwnerAPIView(
ExternalIdViewMixin, SerializerExtensionsAPIViewMixin, RetrieveAPIView
):
"""
Automatically translates an external ID (HashId) to retrieve the Owner
"""
queryset = models.Owner.objects.all()
serializer_class = serializers.OwnerTestSerializer
And use external IDs within your urls:
# urls.py (Django 1 style)
from django.conf.urls import url
from app import views
urlpatterns = [
url(
r'^owners/(?P<external_id>\w+)/$',
views.OwnerAPIView.as_view(),
name='owners'
),
]
HashIdField
You can serialize HashIds as and when required using the HashIdField
:
...
from rest_framework.serializers import ModelSerializer
from rest_framework_serializer_extensions.fields import HashIdField
from app import models
class OwnerSerializer(ModelSerializer):
id = HashIdField(model=models.Owner)
class Meta:
model = models.Owner
fields = ('id', 'name')
The model
argument is used in combination with the source to generate the
HashId. The field will automatically handle serializing/deserializing
external HashIds to internal numeric IDs.
Additional fields
Also provided are the HashIdHyperlinkedIdentityField
and
HashIdHyperlinkedRelatedField
fields. As above, these require a model
argument.