Construir un API REST con Django REST Framework

Las APIs (Interfaces de Programación de Aplicaciones) permiten que diferentes aplicaciones interactúen entre sí mediante el intercambio de datos. En Django, el framework Django REST Framework (DRF) proporciona herramientas poderosas para crear APIs REST de manera rápida y eficiente.

Configuración Inicial


Instalación de Django y DRF

bash
pip install django djangorestframework

Configuración del Proyecto

1Crear un nuevo proyecto y una app:

Para comenzar con tu proyecto en Django, primero crea un nuevo proyecto y una aplicación dentro de él.

bash
django-admin startproject api_project
cd api_project
python manage.py startapp api_app
2Agregar rest_framework al archivo settings.py:

En el archivo settings.py, agrega 'rest_framework' y tu aplicación (api_app) a la lista de INSTALLED_APPS para habilitar Django REST Framework y tu app en el proyecto.

python
INSTALLED_APPS = [
  ...,
  'rest_framework',
  'api_app',
]
3Migraciones iniciales:

Aplica las migraciones para configurar las tablas necesarias en la base de datos.

bash
python manage.py migrate

Creación de APIs REST


Crear un Modelo

Define el modelo Book en api_app/models.py para representar un libro con atributos como título, autor, fecha de publicación e ISBN.

python
from django.db import models

class Book(models.Model):
  title = models.CharField(max_length=100)
  author = models.CharField(max_length=50)
  published_date = models.DateField()
  isbn = models.CharField(max_length=13, unique=True)

  def __str__(self):
      return self.title

Aplica las migraciones:

bash
python manage.py makemigrations
python manage.py migrate

Serializador

Los serializadores convierten los datos entre formatos complejos (por ejemplo, objetos Django) y JSON. Crea un archivo api_app/serializers.py para serializar el modelo Book.

Crea un archivo api_app/serializers.py:

python
from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
  class Meta:
      model = Book
      fields = '__all__'

Vista Basada en Clases (Class-Based View)

Crea una API CRUD utilizando vistas genéricas en api_app/views.py para manejar operaciones de listado, creación, actualización y eliminación de libros.

python
from rest_framework import generics
from .models import Book
from .serializers import BookSerializer

class BookListCreateAPIView(generics.ListCreateAPIView):
  queryset = Book.objects.all()
  serializer_class = BookSerializer

class BookRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
  queryset = Book.objects.all()
  serializer_class = BookSerializer

Configurar URLs

Define las rutas en api_app/urls.py para mapear las vistas de la API a las URLs correspondientes.

python
from django.urls import path
from .views import BookListCreateAPIView, BookRetrieveUpdateDestroyAPIView

urlpatterns = [
  path('books/', BookListCreateAPIView.as_view(), name='book-list-create'),
  path('books/<int:pk>/', BookRetrieveUpdateDestroyAPIView.as_view(), name='book-detail'),
]

Añade las rutas definidas en api_app/urls.py al archivo principal de URLs de tu proyecto api_project/urls.py.

python
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
  path('admin/', admin.site.urls),
  path('api/', include('api_app.urls')),
]

Serialización de Datos


Los serializadores permiten personalizar la forma en que los datos son transformados.

Serializador Personalizado

En lugar de utilizar un ModelSerializer, puedes crear un serializador personalizado para tener mayor control sobre el proceso de serialización y deserialización. Aquí tienes un ejemplo de un serializador personalizado para el modelo Book:

python
from rest_framework import serializers
from .models import Book

class CustomBookSerializer(serializers.Serializer):
  id = serializers.IntegerField(read_only=True)
  title = serializers.CharField(max_length=100)
  author = serializers.CharField(max_length=50)
  published_date = serializers.DateField()

  def create(self, validated_data):
      return Book.objects.create(**validated_data)

  def update(self, instance, validated_data):
      instance.title = validated_data.get('title', instance.title)
      instance.author = validated_data.get('author', instance.author)
      instance.published_date = validated_data.get('published_date', instance.published_date)
      instance.save()
      return instance

Autenticación y Permisos


Configuración de Autenticación

DRF incluye autenticación por token utilizando el paquete djangorestframework-simplejwt.

1Instalar la app:

Primero, instala la librería djangorestframework-simplejwt:

bash
pip install djangorestframework-simplejwt
2Actualizar settings.py:

Agrega la configuración necesaria en el archivo settings.py para habilitar la autenticación con JWT:

python
INSTALLED_APPS += ['rest_framework_simplejwt']

 REST_FRAMEWORK = {
     'DEFAULT_AUTHENTICATION_CLASSES': (
         'rest_framework_simplejwt.authentication.JWTAuthentication',
     ),
     'DEFAULT_PERMISSION_CLASSES': (
         'rest_framework.permissions.IsAuthenticated',
     ),
 }
3Configurar URLs para autenticación:

Agrega las rutas necesarias en api_project/urls.py para permitir la obtención y actualización de tokens JWT:

python
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

 urlpatterns += [
     path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
     path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
 ]

Permisos Personalizados

Crea un permiso personalizado en api_app/permissions.py para permitir que solo el autor de un recurso lo modifique:

python
from rest_framework.permissions import BasePermission

class IsAuthorOrReadOnly(BasePermission):
  def has_object_permission(self, request, view, obj):
      if request.method in ['GET', 'HEAD', 'OPTIONS']:
          return True
      return obj.author == request.user

Aplica el permiso personalizado en una vista en api_app/views.py para que solo el autor o usuarios autenticados puedan modificar los libros:

python
from rest_framework.permissions import IsAuthenticated
from .permissions import IsAuthorOrReadOnly

class BookRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
  queryset = Book.objects.all()
  serializer_class = BookSerializer
  permission_classes = [IsAuthenticated, IsAuthorOrReadOnly]

Paginación


Configura la paginación en settings.py para limitar la cantidad de resultados por página:

python
REST_FRAMEWORK['DEFAULT_PAGINATION_CLASS'] = 'rest_framework.pagination.PageNumberPagination'
REST_FRAMEWORK['PAGE_SIZE'] = 10

Documentación Automática


Usa drf-spectacular para documentar tus APIs de manera automática.

1Instalación:
bash
pip install drf-spectacular
2Configura settings.py:

Añade la siguiente configuración para usar drf-spectacular como el generador de esquemas para la documentación de la API.

python
REST_FRAMEWORK['DEFAULT_SCHEMA_CLASS'] = 'drf_spectacular.openapi.AutoSchema'
3Agregar rutas:

Añade las rutas para generar el esquema y mostrar la documentación interactiva de la API usando Swagger en urls.py.

python
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView

 urlpatterns += [
     path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
     path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
 ]

Recursos adicionales

Si tienes alguna duda, te comparto un proyecto adicional donde creamos otra API con Django Rest Framework: