Este site usa cookies e tecnologias afins que nos ajudam a oferecer uma melhor experiência. Ao clicar no botão "Aceitar" ou continuar sua navegação você concorda com o uso de cookies.

Aceitar
Django Rest Framework: Construindo APIs RESTful com Django.

django

Django Rest Framework: Construindo APIs RESTful com Django.

Elias
Escrito por Elias

No desenvolvimento de aplicações atuais, especialmente quando se trata de separar front-end e back-end, as APIs RESTful tornaram-se um componente essencial. API (Application Programming Interface) é um conjunto de rotinas e padrões de programação que permite a comunicação entre sistemas diferentes. E, no contexto de aplicações web, REST (Representational State Transfer) é o padrão amplamente adotado para criação de APIs.

Por que REST é tão popular? Simples. Ele permite que sistemas possam se comunicar de forma eficiente e escalável, utilizando operações HTTP como GET, POST, PUT e DELETE para manipular recursos. Mas, como sempre, a teoria é uma coisa; na prática, pode ser bem mais desafiador. É aí que entra o Django REST Framework (DRF).

O Django REST Framework é uma biblioteca poderosa que facilita a criação de APIs RESTful com Django. Ele oferece uma série de ferramentas que resolvem os problemas comuns na criação de APIs, como serialização de dados, controle de permissões, autenticação, tratamento de erros, e muito mais. E, como a maioria das bibliotecas Django, o DRF é altamente modular e extensível, o que permite que você customize quase todos os aspectos da sua API.

Vamos direto ao ponto: nesta postagem, veremos como construir APIs RESTful utilizando o Django REST Framework, cobrindo desde a instalação e configuração básica até práticas avançadas como autenticação, filtragem, paginação, otimização e segurança…

Instalação e Configuração do Django REST Framework

Antes de qualquer coisa, você precisa ter um projeto Django em funcionamento. Se você ainda não tem um, basta criar um com os comandos:

django-admin startproject minhaapi .
Bash

Agora, instale o Django REST Framework:

pip install djangorestframework
Bash

Em seguida, adicione o rest_framework à lista de INSTALLED_APPS no arquivo settings.py:

INSTALLED_APPS = [
    # Outros apps do Django...
    'rest_framework',
]
Python

Isso habilita o Django REST Framework no seu projeto.

Configurações Iniciais

No mesmo arquivo settings.py, podemos adicionar uma configuração básica para o DRF. Ela vai definir o comportamento padrão de permissões, autenticação e paginação da nossa API. Veja um exemplo simples:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',  # <- Permite acesso a qualquer usuário
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',  # <- Autenticação baseada em sessão
        'rest_framework.authentication.TokenAuthentication',    # <- Autenticação por token
    ],
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10  # Número padrão de itens por página
}
Python

Essa configuração é um ponto de partida. Definimos que a API permite qualquer requisição por enquanto (AllowAny), que ela pode usar autenticação por sessão ou por token, e que a paginação retorna 10 itens por página.

Agora que já temos o Django REST Framework instalado e configurado, vamos criar nossa primeira API!

Serializers: Convertendo Dados para APIs

Os serializers no Django REST Framework são responsáveis por converter instâncias de modelos do Django (ou outros tipos de dados complexos) em formatos simples que podem ser facilmente renderizados em JSON, ou outros formatos adequados para uma API.

Há boatos que é possivel renderizar xml com django-rest-framework mas eu nunca vi como. Se você sabe como, ou já ouviu falar deixe um comentario aqui nesta postagem .Eu gostaria muito de saber como isso funciona.

Imagine que temos um modelo de produto em nosso sistema Django:

from django.db import models

class Produto(models.Model):
    nome = models.CharField(max_length=100)
    descricao = models.TextField()
    preco = models.DecimalField(max_digits=10, decimal_places=2)
    data_criacao = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.nome
Python

Para expor esses dados via API, precisamos de um serializer que vai converter esse modelo para JSON e vice-versa. Veja como criar um serializer básico:

from rest_framework import serializers
from .models import Produto

class ProdutoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Produto
        fields = ['id', 'nome', 'descricao', 'preco', 'data_criacao']
Python

O ProdutoSerializer usa o ModelSerializer, que automaticamente mapeia os campos do modelo Produto. Isso nos poupa de definir manualmente cada campo no serializer, mas você pode fazer isso se precisar de mais controle sobre o que vai ser serializado.

Um serializer mais manual ficaria assim:

class ProdutoSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    nome = serializers.CharField(max_length=100)
    descricao = serializers.CharField()
    preco = serializers.DecimalField(max_digits=10, decimal_places=2)
    data_criacao = serializers.DateTimeField()
Python

Este exemplo dá mais controle sobre o comportamento dos campos individuais, mas na maioria dos casos, o ModelSerializer é suficiente.

Validação de Dados

Uma das grandes vantagens dos serializers é que eles não apenas convertem dados, mas também validam automaticamente as entradas dos usuários. O ProdutoSerializer validará o tipo de dado, comprimento dos campos, entre outras coisas.

Se você quiser adicionar validações personalizadas, pode sobrescrever o método validate() no serializer:

class ProdutoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Produto
        fields = '__all__'

    def validate_preco(self, value):
        if value <= 0:
            raise serializers.ValidationError("O preço deve ser maior que zero.")
        return value
Python

Neste exemplo, garantimos que o preço do produto não pode ser negativo. O Django REST Framework trata a validação automaticamente e retorna mensagens de erro apropriadas.

Viewsets: Controlando as Requisições da API

Os Viewsets no Django REST Framework são uma forma poderosa de lidar com as requisições da API de forma eficiente. Eles combinam as funcionalidades de várias Views tradicionais do Django em uma única classe, permitindo um código mais conciso e fácil de manter.

Uma Viewset simplifica bastante as coisas. Ela agrupa as ações de listagem, detalhamento, criação, atualização e deleção em uma única classe.

Aqui está um exemplo de um Viewset para nosso modelo Produto:

from rest_framework import viewsets
from .models import Produto
from .serializers import ProdutoSerializer

class ProdutoViewSet(viewsets.ModelViewSet):
    queryset = Produto.objects.all()
    serializer_class = ProdutoSerializer
Python

Com isso, o DRF automaticamente cria as rotas e métodos HTTP necessários para listar produtos, criar novos, atualizar e deletar, tudo em uma única classe. Isso economiza muito código repetitivo.

O ModelViewSet inclui as seguintes ações por padrão:

  • list(): Retorna uma lista de objetos.
  • retrieve(): Retorna um objeto específico.
  • create(): Cria um novo objeto.
  • update(): Atualiza um objeto existente.
  • destroy(): Remove um objeto.

Se quiser personalizar essas ações, você pode sobrescrevê-las. Por exemplo, se você quiser modificar o comportamento de listagem:

class ProdutoViewSet(viewsets.ModelViewSet):
    queryset = Produto.objects.all()
    serializer_class = ProdutoSerializer

    def list(self, request):
        queryset = Produto.objects.filter(preco__gte=10)  # Exemplo: apenas produtos com preço acima de 10 dinheiros
        serializer = ProdutoSerializer(queryset, many=True)
        return Response(serializer.data)
Python

Isso permite adicionar lógicas específicas para cada operação.

Routers: Mapeando URLs para as Viewsets

Para expor nossas Viewsets via URLs, o Django REST Framework oferece o conceito de routers, que simplificam o processo de mapeamento das URLs da API.

Aqui está como podemos adicionar um router para nossa API de produtos:

from rest_framework.routers import DefaultRouter
from .views import ProdutoViewSet

router = DefaultRouter()
router.register(r'produtos', ProdutoViewSet)

urlpatterns = [
    path('', include(router.urls)),
]
Python

O DefaultRouter gera automaticamente todas as rotas necessárias para as operações CRUD. Ele vai criar URLs como:

  • /produtos/: Para listar e criar produtos.
  • /produtos/{id}/: Para recuperar, atualizar ou deletar um produto específico.

Isso elimina a necessidade de mapear manualmente cada URL, tornando o código mais limpo e fácil de manter.

Se precisar de rotas personalizadas, como uma rota para buscar produtos por nome, você pode fazer isso criando uma Action:

from rest_framework.decorators import action
from rest_framework.response import Response

class ProdutoViewSet(viewsets.ModelViewSet):
    queryset = Produto.objects.all()
    serializer_class = ProdutoSerializer

    @action(detail=False, methods=['get'], url_path='buscar')
    def buscar_produto(self, request):
        nome = request.query_params.get('nome')
        produtos = Produto.objects.filter(nome__icontains=nome)
        serializer = self.get_serializer(produtos, many=True)
        return Response(serializer.data)
Python

Isso cria uma nova rota /produtos/buscar/?nome=play5-barato, que retorna produtos com o nome que contém o parâmetro passado.

Permissões e Autenticação

Uma API aberta para o público geral pode ser perigosa, especialmente quando estamos lidando com dados sensíveis. Por isso, garantir que apenas usuários autorizados possam acessar ou modificar recursos é essencial. O Django REST Framework torna esse processo muito fácil com seu sistema de permissões e autenticação.

Permissões no Django REST Framework

As permissões definem quem pode acessar certas views ou realizar certas ações. O Django REST Framework já traz algumas permissões básicas, que podem ser configuradas diretamente nas views ou viewsets.

  • AllowAny: Permite que qualquer pessoa acesse a view (inclusive usuários anônimos).
  • IsAuthenticated: Apenas usuários autenticados podem acessar.
  • IsAdminUser: Apenas administradores podem acessar.
  • IsAuthenticatedOrReadOnly: Usuários autenticados podem fazer tudo; usuários anônimos só podem ler.

Podemos aplicar essas permissões diretamente nas viewsets:

from rest_framework.permissions import IsAuthenticated

class ProdutoViewSet(viewsets.ModelViewSet):
    queryset = Produto.objects.all()
    serializer_class = ProdutoSerializer
    permission_classes = [IsAuthenticated]
Python

Aqui, apenas usuários logados poderão acessar as rotas da API de produtos.

Autenticação com Tokens

A autenticação baseada em tokens é uma das formas mais comuns de proteger APIs RESTful. O DRF oferece suporte nativo para autenticação com tokens, permitindo que os usuários façam login e recebam um token único, que será enviado com cada requisição subsequente para provar sua identidade.

Para habilitar a autenticação por token, instale o pacote djangorestframework-simplejwt:

pip install djangorestframework-simplejwt
Bash

Adicione as classes de autenticação ao settings.py:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
}
Python

Agora, configure as rotas para obter e atualizar tokens no seu urls.py:

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'),
]
Python

Com isso, os usuários poderão obter um token de autenticação enviando suas credenciais (usuário e senha) para /api/token/. O token será então usado em cada requisição subsequente:

curl -X POST http://localhost:8000/api/token/ -d "username=admin&password=12345"
Python

Isso retornará um token JWT, que deve ser enviado no cabeçalho Authorization em cada requisição subsequente:

curl -H "Authorization: Bearer <token>" http://localhost:8000/produtos/
Python

Filtragem, Ordenação e Paginação

APIs sem a capacidade de filtrar, ordenar e paginá-las podem se tornar um pesadelo de performance à medida que os dados crescem. O Django REST Framework oferece suporte nativo para esses recursos.

Filtragem

A filtragem permite que os clientes da API restrinjam os resultados com base em critérios específicos. Podemos usar o pacote django-filter para facilitar essa tarefa:

pip install django-filter
Bash

Em settings.py, adicione a configuração para habilitar o django-filter no DRF:

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
}
Python

Agora, no views.py, podemos adicionar filtragem a nossa Viewset de produtos:

from django_filters.rest_framework import DjangoFilterBackend

class ProdutoViewSet(viewsets.ModelViewSet):
    queryset = Produto.objects.all()
    serializer_class = ProdutoSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['nome', 'preco']
Python

Com isso, podemos filtrar produtos por nome e preco diretamente na URL:

http://localhost:8000/produtos/?nome=Mouse&preco=50
Python

Ordenação

Além de filtrar, podemos ordenar os resultados da API. Para isso, usamos a classe OrderingFilter:

from rest_framework.filters import OrderingFilter

class ProdutoViewSet(viewsets.ModelViewSet):
    queryset = Produto.objects.all()
    serializer_class = ProdutoSerializer
    filter_backends = [DjangoFilterBackend, OrderingFilter]
    filterset_fields = ['nome', 'preco']
    ordering_fields = ['preco', 'data_criacao']
Python

Agora, podemos ordenar os produtos por preco ou data_criacao:

http://localhost:8000/produtos/?ordering=preco
http://localhost:8000/produtos/?ordering=-preco
Python

Paginação

Paginar os resultados é crucial para APIs que podem retornar grandes volumes de dados. No Django REST Framework, a paginação pode ser configurada globalmente no settings.py ou individualmente em cada Viewset.

Aqui está a configuração global para usar paginação baseada em números de página:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10
}
Python

Com essa configuração, a resposta da API será automaticamente paginada em blocos de 10 itens por vez. Para navegar pelas páginas, basta adicionar o parâmetro page à URL:

http://localhost:8000/produtos/?page=2
Python

Testando APIs RESTful

Uma das melhores práticas no desenvolvimento de software é testar suas APIs. Testes garantem que seu código funcione conforme esperado e que futuras alterações não quebrem nada.

O Django REST Framework oferece o APIClient, uma ferramenta que facilita a escrita de testes para APIs. Vamos ver como testar nossa API de produtos.

from rest_framework.test import APITestCase
from django.urls import reverse
from rest_framework import status
from .models import Produto

class ProdutoAPITest(APITestCase):
    
    def setUp(self):
        self.produto = Produto.objects.create(
            nome="Teclado",
            descricao="Teclado mecânico",
            preco=150.00
        )
    
    def test_listar_produtos(self):
        url = reverse('produto-list')
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
    
    def test_criar_produto(self):
        url = reverse('produto-list')
        data = {'nome': 'Mouse', 'descricao': 'Mouse óptico', 'preco': 50.00}
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
Python

No teste acima, usamos o APITestCase para testar duas coisas: listar os produtos e criar um novo produto. Isso garante que nossas operações básicas da API estão funcionando como esperado.

Só Para lembrar: Caso precise se aprofundar mais nos testes
unitarios da um pulo na postagem acima ;D

Melhorando Performance com Viewsets Otimizados

Performance é sempre uma preocupação, especialmente quando se trata de APIs que podem ser acessadas por múltiplos clientes simultaneamente. O Django REST Framework permite otimizar as consultas ao banco de dados usando os métodos select_related() e prefetch_related().

Esses métodos são úteis quando estamos lidando com relações entre modelos, como ForeignKey e ManyToManyField.

Imagine que cada produto tenha um categoria, que é uma ForeignKey. Para evitar múltiplas consultas ao banco, podemos usar select_related:

class ProdutoViewSet(viewsets.ModelViewSet):
    queryset = Produto.objects.select_related('categoria').all()
    serializer_class = ProdutoSerializer
Python

O select_related() carrega a relação ForeignKey em uma única consulta, reduzindo a sobrecarga no banco de dados.

Evitando o Problema N+1

Um dos problemas mais comuns em APIs mal otimizadas é o N+1 problem. Isso acontece quando a aplicação faz uma consulta principal (a primeira) e depois faz N outras consultas para obter dados relacionados, o que é extremamente ineficiente.

Por exemplo, se tivermos uma lista de produtos, e cada produto tiver uma relação com uma categoria, sem select_related(), o Django faria uma consulta para listar os produtos e, depois, N consultas para cada uma das categorias associadas. O uso de select_related() evita isso.

Tratamento de Erros e Exceções

Ninguém gosta de ver erros sem sentido ao usar uma API. O Django REST Framework facilita o tratamento de exceções e erros para garantir que as respostas da API sejam claras e informativas.

Por padrão, o DRF já lida com muitos erros comuns (como 404 Not Found ou 400 Bad Request). No entanto, você pode personalizar o comportamento criando suas próprias handlers de erro.

Aqui está um exemplo de como capturar exceções e retornar uma resposta customizada:

from rest_framework.views import exception_handler

def custom_exception_handler(exc, context):
    response = exception_handler(exc, context)
    
    if response is not None:
        response.data['status_code'] = response.status_code
    
    return response
Python

Em settings.py, adicione a referência para esse handler:

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'meuprojeto.utils.custom_exception_handler', 
}
Python

Agora, todas as exceções serão tratadas pelo seu handler customizado, onde você pode adicionar informações extras à resposta, como status code, mensagens mais amigáveis, etc.

Implementando Versionamento de API

Versionar uma API é crucial quando há a necessidade de fazer atualizações sem quebrar a compatibilidade com clientes antigos. O Django REST Framework facilita a implementação de versionamento, permitindo que você diferencie as versões da API nas URLs ou nos cabeçalhos.

Versionamento nas URLs

A abordagem mais comum é incluir a versão na URL. Aqui está um exemplo de como fazer isso:

from rest_framework.versioning import URLPathVersioning

REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
}

urlpatterns = [
    path('api/v1/produtos/', ProdutoViewSet.as_view(), name='produtos-v1'),
    path('api/v2/produtos/', ProdutoViewSetV2.as_view(), name='produtos-v2'),
]
Python

Agora você tem duas versões da API rodando ao mesmo tempo. A versão v2 pode conter mudanças significativas sem afetar os clientes que ainda estão usando a v1.

Documentação Automática com Swagger

Uma boa documentação é essencial para qualquer API. O Django REST Framework pode gerar automaticamente uma documentação interativa para sua API usando ferramentas como o drf-yasg ou o Swagger.

Instale o pacote:

pip install drf-yasg
Python

Em seguida, adicione a configuração em urls.py:

from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi

schema_view = get_schema_view(
    openapi.Info(
        title="Minha API",
        default_version='v1',
        description="Documentação da API",
    ),
    public=True,
    permission_classes=(permissions.AllowAny,),
)

urlpatterns = [
    path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
]
Python

Agora você pode acessar a documentação completa da sua API em /swagger/. A interface gerada pelo Swagger permite que os desenvolvedores vejam todas as rotas disponíveis, além de testar as requisições diretamente na página.

Conclusão

Neste artigo, detalhamos como construir APIs RESTful usando o Django REST Framework, passando desde a instalação e configuração até conceitos mais avançados, como autenticação por token, filtragem, paginação e otimização de consultas.

Construir APIs pode parecer desafiador no início, mas o Django REST Framework oferece ferramentas maravilhosas para facilitar o desenvolvimento, mantendo um alto nível de flexibilidade e extensibilidade. Além disso, com boas práticas de segurança e documentação, a API que você criar estará pronta para ser consumida de forma eficiente e segura.

Se seguir as dicas e exemplos mostrados aqui, você terá uma API RESTful pronta para escalar.

Se você chegou até aqui, parabéns! Agora é hora de colocar a mão na massa e construir suas próprias APIs.