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 .
BashAgora, instale o Django REST Framework:
pip install djangorestframework
BashEm seguida, adicione o rest_framework
à lista de INSTALLED_APPS no arquivo settings.py
:
INSTALLED_APPS = [
# Outros apps do Django...
'rest_framework',
]
PythonIsso 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
}
PythonEssa 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
PythonPara 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']
PythonO 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()
PythonEste 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
PythonNeste 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
PythonCom 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)
PythonIsso 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)),
]
PythonO 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)
PythonIsso 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]
PythonAqui, 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
BashAdicione as classes de autenticação ao settings.py
:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
}
PythonAgora, 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'),
]
PythonCom 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"
PythonIsso 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/
PythonFiltragem, 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
BashEm settings.py
, adicione a configuração para habilitar o django-filter
no DRF:
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
}
PythonAgora, 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']
PythonCom isso, podemos filtrar produtos por nome
e preco
diretamente na URL:
http://localhost:8000/produtos/?nome=Mouse&preco=50
PythonOrdenaçã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']
PythonAgora, podemos ordenar os produtos por preco
ou data_criacao
:
http://localhost:8000/produtos/?ordering=preco
http://localhost:8000/produtos/?ordering=-preco
PythonPaginaçã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
}
PythonCom 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
PythonTestando 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)
PythonNo 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.
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
PythonO 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
PythonEm settings.py
, adicione a referência para esse handler:
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'meuprojeto.utils.custom_exception_handler',
}
PythonAgora, 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'),
]
PythonAgora 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
PythonEm 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'),
]
PythonAgora 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.