Projeto exemplo para entendimento e criação de aplicações Django com Django REST Framework.
- 📚 Conceitos
- 📖 Instalação e configuração básica
- 📊 Configuração intermediária
- 🔐 Configuração avançada
- 👨💻 Testando APIs
- 🕹️ Abrir e rodar o projeto escola
Interface de comunicação de aplicações de forma programática.
HTTP é um design sem estado, ou seja, toda requisição é única. A responsabilidade de lembrar dos estados é do cliente.
Gramática da língua portuguesa tem tudo a ver com endpoints, pois usamos substantivos e verbos para criá-los.
Um
'resource'
pode ser, por exemplo, um modelo da nossa aplicação:
- Categorias
- Produtos
Nós fazemos as operações CRUD através de
URI
específicas na nossa aplicação, por exemplo:
- sistema.com.br/api/v1/produtos
- sistema.com.br/api/v1/categorias
Estas URIs são os endpoints
Um endpoint pode representar uma coleção de registros ou um registro individual.
Coleção
sistema.com.br/api/v1/produtos
Individual
sistema.com.br/api/v1/produtos/42
Indica uma ação.
C
Create
POST
R
Read
GET
U
Update
PUT
D
Delete
DELETE
As requisições (requests) é a solicitação ao servidor.
Exemplo:
/api/v1/produtos?order=desc&limit=10
Tudo que vem depois do ?
é chamado de querystring
- Accept: Específica o formato de arquivo.
- Accept-Language: Define lingua de retorno.
- Cache-Control: Específica se o conteúdo pode ser consumido do cache e em quanto tempo o cache é atualizado.
application/json
define um padrão de retorno.
/api/v1/produtos
/api/v2/produtos
Preparar a Resposta.
Detalhes avaliados da solicitação:
- Na requisição existe query string?
- Qual foi o verbo HTTP que realizou a ação?
- Quai são os dados do cabeçalho?
- Qual o formato requisitado?
- Preparar os dados da coleção ou indivíduo do recurso solicitado.
Dados retornados:
- data (dados)
- Cabeçalho
- Content-Type: Accept encaminhado.
- Las-Modified: Data de criação ou última modificação.
- Expires: Até quando este dado pode ser considerado atual
- Status: 200 OK (código de status HTTP)
- Fazendo uso de cache.
- Limitar número de requisições por período (segundos).
- Autenticação (quem você é)
- Token (chave publica)
- Autorização (o que você pode fazer)
📁 Entendendo sobre a segurança de APIs REST
Model Serialization
, DRF mapeia os Django Models
e provê uma facilidade muito grande a trabalhar com os objetos Python e serializar/deserializar para JSON.
- Instale o django-rest-framework
pip install djangorestframework markdown django-filter
pip freeze > requirements.txt
- Adicionar
rest_framework
emINSTALLED_APPS
no arquivoescola/settings.py
[
'django_filters',
'rest_framework'
]
- Adicionar configurações de
DRF
no arquivoescola/settings.py
# DRF
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
)
}
- Incluir URLs padrão em
urlpatterns
no arquivoescola/urls.py
path('auth/', include('rest_framework.urls')),
📁 ViewSets
- Otimiza a criação de urls, gera automaticamente através do router as operações CRUD de apenas um modelo.
- Sobrescreva o método get para acessar, por exemplo, todas a avaliações de um determinado curso
(v2/cursos/1/avaliacoes)
.
Existem 3 formas de retornar modelos relacionados em sua API.
Retorna os objetos conforme parametrizado no seu Serializer das avaliações relacionadas.
avaliacoes = AvaliacaoSerializer(many=True, read_only=True)
Adicionar um link para acesso das avaliações relacionadas.
avaliacoes = serializers.HyperlinkedRelatedField(
many=True,
read_only=True,
view_name='avaliacao-detail'
)
Adiciona apenas a chave primária (id) das avaliações relacionadas.
avaliacoes = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
Em
escola/settings.py
adicione aoREST_FRAMEWORK
:
REST_FRAMEWORK = {
...,
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 2
}
Adiciona automaticamente 3 atributos ao retorno.
{
"count": "<int:contagem de páginas>",
"next": "<link:página anterior>",
"previous": "<link:próxima página>",
}
Obs: Em métodos sobrescritos você deverá adicionar manualmente a paginação conforme exemplo que ocorre em
CursoViewSet
:
@action(detail=True, methods=['get'])
def avaliacoes(self, request, pk=None):
self.pagination_class.page_size = 2
avaliacoes = Avaliacao.objects.filter(curso_id=pk)
page = self.paginate_queryset(avaliacoes)
if page is not None:
serializer = AvaliacaoSerializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = AvaliacaoSerializer(avaliacoes, many=True)
return Response(serializer.data)
Configurações em
escola/settings.py
:
- Adicionar aos INSTALLED_APPS:
{
...,
'rest_framework.authtoken',
...
}
- Comentar autenticação via sessão do
REST_FRAMEWORK
e adicionar:
'DEFAULT_AUTHENTICATION_CLASSES': (
# 'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
),
- Realizar migração
python manage.py migrate
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User
admin = User.objects.get(id=1)
token = Token.objects.create(user=admin)
print(token.key)
Token Admin: 11c573b2dab073aef36698a9600a43aa8cb70d99
Obs: É possível realizar a criação via
Administração do Django
Permissões dizem respeito aos verbos HTTP (CRUD) que o usuário tem permissão para executar.
Através do
Administração do Django
é possível realizar essa configuração de permissão sobre um modelo específico para cada usuário sem tornar o usuário administrador.
- Criação de um arquivo chamado
permissions.py
no diretório do app 1.1 Exemplo emcursos/permissions.py
- Importação de módulo criado nas
views
e inserção no início do ViewSet 2.1 Exemplo emcursos/views.py
from rest_framework import permissions
class CursoViewSet(viewsets.ModelViewSet):
permission_classes = (
EhSuperUser,
permissions.DjangoModelPermissions,
),
...
Similar a permissões, porém ele vai limitar as requisições por um determinado período para os clientes.
A configuração será global configurada no
REST_FRAMEWORK
emcursos/settings.py
:
- Anônimos podem fazer podem fazer 5 requisições por minuto e
- Usuários autenticados podem fazer 10 requisições por minuto.
{
...,
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
'anon': '5/minute', # second, day, month, year
'user': '10/minute'
}
}
Restrição: Avaliações não podem ser maior que 5 (avaliacao).
Criação de uma avaliação:
{
"curso": 2,
"nome": "Maria da Silva",
"email": "maria@gmail.com",
"avaliacao": 9
}
Retorno:
{
"avaliacao": [
"A avaliação precisa ser um inteiro entre 1 e 5"
]
}
- Em
cursos/seralizers.py
criar a validação para a classe 1.1 A função por padrão deve começar comvalidate_
def validate_avaliacao(self, valor):
if valor in range(1, 6): # 1, 2, 3, 4, 5
return valor
raise serializers.ValidationError('A avaliação precisa ser um inteiro entre 1 e 5')
Adicionar atributo no retorno com a
média das avaliações
- Criar atributo e especificar o tipo
media_avaliacoes = serializers.SerializerMethodField()
- Adicionar na lista de dados que serão apresentados
fields = (
'media_avaliacoes'
)
- Criar função 3.1 Nome da função iniciado em _get e 3.2 Restante do nome é o atributo que será criado
def get_media_avaliacoes(self, obj):
media = obj.avaliacoes.aggregate(Avg('avaliacao')).get('avaliacao__avg')
if media is None:
return 0
return round(media * 2) / 2
Ao inves de criar uma função para atualizar a média em cada requisição, criar um campo no modelo e atualizar o campo a cada atualização.
A pasta
tests
no diretório raiz contém todos os testes com descrição em cada arquivo.
Crie testes que façam sentido para a sua aplicação!
Módulo para fazer requisições.
pip install requests
📁 Arquivos de testes para requests
pip install jsonpath
Vantagem: acessar diretamente os dados com maior facilidade e realizar filtros nativamente
pip install pytest
📁 Pytest
Comando para executar testes pelo arquivo pytest:
pytest .\tests\test_pytest.py
Obs: o pk/id dos métodos PUT e POST (requests) deve ser atualizado para realização dos testes.
📁 JSON de importação Insominia
Instruções necessárias para abrir e executar o projeto
Instale o Python 3
- Clone o repositório e entre na pasta:
git clone https://github.com/rauldosS/django-rest-framework.git
cd/django-rest-framework
- Crie um ambiente virtual:
Linux
virtualenv <nome_da_virtualenv>
Windows
python -m venv <nome_da_virtualenv>
- Ative o ambiente virtual que você acabou de criar:
Linux
source <nome_da_virtualenv>/bin/activate
Windows
.\<nome_da_virtualenv>\Scripts\activate
- Instale os pacotes de desenvolvimento local:
pip install -r requirements.txt
- Execute as migrações:
python manage.py migrate
Rode o servidor de desenvolvimento:
python manage.py runserver