Alura > Cursos de Programação > Cursos de Python > Conteúdos de Python > Primeiras aulas do curso Django REST Framework: trabalhando com permissões, documentação, limitações, CORS e deploy na AWS

Django REST Framework: trabalhando com permissões, documentação, limitações, CORS e deploy na AWS

Limitando requisições - Apresentação

Olá, meu nome é Laís Urano, sou instrutora na Escola de Programação da Alura e vou acompanhar você neste curso de Django REST Framework.

Audiodescrição: Laís Urano se identifica como uma mulher parda. Possui olhos castanhos, cabelos cacheados e volumosos, também castanhos, com mechas azuis. Possui piercing no nariz e usa batom escuro. No corpo, utiliza uma camiseta verde oliva e um colar dourado. Atrás dela, os estúdios da Alura, onde há uma parede lisa e uma estante à direita, iluminadas em tons de verde e azul.

Para quem é o curso?

Este conteúdo é para quem deseja aprofundar conhecimentos sobre desenvolvimento de APIs com Python e Django REST Framework.

Pré-requisitos

Será necessário ter conhecimento em Python e em Django. Além disso, este curso é uma continuação direta de dois cursos da Formação de Django REST Framework. Portanto, é importante estar familiarizado com os projetos anteriores dessa formação.

O que aprenderemos?

Veremos tudo isso no projeto de uma API de escola. Vamos começar?

Limitando requisições - Ordenando as Listas de Objetos

Nos cursos anteriores, trabalhamos no desenvolvimento de uma API de uma escola que possui estudantes, cursos e matrículas. Todo o conteúdo que precisávamos desenvolver estava em cartões no Trello do projeto.

Desenvolvemos a API, adicionamos autenticações, validações, filtros, versionamento e diversos outros pontos. Agora, vamos continuar esse projeto, focando em outros pontos importantes para o desenvolvimento da API.

Revisando a rota

O primeiro cartão no backlog, chamado "Ordenação", indica a ordem na qual vamos começar. Mas antes, vamos revisar a API Root, a rota, para ver como ela está.

Acessando a página da API Root no navegador, notaremos três rotas: /estudantes, /cursos e /matriculas.

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "estudantes": "http://127.0.0.1:8000/estudiantes/",
    "cursos": "http://127.0.0.1:8000/cursos/",
    "matriculas": "http://127.0.0.1:8000/matriculas/"
}

Podemos clicar em cada rota para acessá-la e verificar os estudantes e cursos que cadastramos. Já na rota de matrícula, veremos campos para cadastrar qualquer estudante.

Nessa rota, cadastraremos a Alícia no período matutino, no curso CPOO1.

Com login feito, essa matrícula cadastrada, e vendo que conseguimos acessar as rotas, podemos acessar o VS Code, em cujo terminal está rodando o servidor.

Ordenando objetos

No terminal do VS Code, temos uma mensagem de aviso, de lista não ordenada (UnorderedObjectListWarning), indicando que podemos apresentar resultados inconsistentes, devido ao fato desse modelo não estar ordenado quando o recebemos.

… UnorderedObjectListWarning: Pagination may yield to inconsistent results with an unordered object_list …

Acessaremos o explorador lateral para acessar o arquivo views.py, dentro da pasta "escola". Em seu interior, há várias classes com viewsets de estudante, curso, matrícula e todos os outros que definimos.

Na primeira linha de cada viewset, definimos o queryset, que está capturando os objetos do modelo. Nesse momento, não ordenamos esses objetos, apenas os capturamos.

Entretanto, por padrão, a API ordena tudo por ID. Acessando a API no navegador e entrando na rota /estudantes, observaremos cada pessoa estudante ordenada por ID.

Na parte superior direita da página com a rota de estudantes, também adicionamos um botão de filtro. Clicando nele, vemos uma janela na qual é possível ordenar por nome, na ordem ascendente ou na ordem descendente.

Clicaremos na opção "nome - ascendente", impedindo que ele ordene por ID e resolvendo o problema.

A mensagem que recebemos não indica um erro, mas sim um aviso, informando que não estamos garantindo essa ordenação por ID e estamos esperando que a própria API faça isso para nós. Portanto, precisamos indicar no viewset, no qual determinamos como os dados são capturados, que ele será ordenado também. Precisamos mostrar uma lista ordenada de objetos.

Ao voltar para o Trello do projeto e acessar o cartão "Ordenação", no backlog, podemos ler as regras que temos que implementar:

Regras:

> * Estudante:
> 
    > * campo `id`;
    > 
> * Curso:
> 
    > * campo `id`;
    > 
> * Matrícula:
> 
    > * campo `id`;

Como podemos garantir essa ordenação?

No navegador, abriremos uma nova guia e pesquisaremos por "queryset api order".

queryset api order

Clicaremos no primeiro link para acessar a documentação do Django.

Recomendamos digitar e pesquisar essas informações em inglês, porque é mais fácil de achar. Mesmo existindo a possibilidade de tradução, muitos desses conteúdos não são traduzidos.

Dentro dessa página, abriremos o campo de pesquisa com "Ctrl+F" e pesquisaremos a palavra "order".

order

Pressionaremos "Enter" até achar a seção do método orderBy. Esta informa que o orderBy recolhe informações da opção ordering do Meta.

Esse Meta deve ser definido na classe do Serializer, mas não fizemos isso nos Serializers. Mesmo assim, caso não definamos, ele informa que capturará as informações direto do banco de dados, de acordo com o que foi armazenado.

Nesse caso, como os dados são armazenados por ID, ele está ordenando por ID.

Como poderemos informar a ordem no viewset, caso não tenhamos informado no ordering do Serializer? Podemos adicionar o método orderBy ao capturar esse objeto para retornar o parâmetro que usaremos para ordenar - neste caso, o ID.

Dessa forma, ele ordenará por essas informações.

Adicionando o orderBy()

Voltando ao VS Code, no arquivo views.py, faremos exatamente esse processo. Fecharemos a aba lateral do explorador para focar melhor no projeto.

Entre as chaves da classe EstudanteViewSet, acessaremos o final da linha do queryset de estudantes e adicionar .orderBy() conectado ao Estudante.objects.all(). Entre os parênteses, digitaremos o id, entre aspas duplas.

views.py:

class EstudanteViewSet(viewsets.ModelViewSet):
    queryset = Estudante.objects.all().order_by("id")
    # Código omitido

Isso ordenará as pessoas estudantes por ID.

Copiaremos esse .orderBy("id") e colaremos no viewsets das outras classes.

class CursoViewSet(viewsets.ModelViewSet):
    queryset = Curso.objects.all().order_by("id")
    # Código omitido

class MatriculaViewSet(viewsets.ModelViewSet):
    queryset = Matricula.objects.all().order_by("id")
        # Código omitido

Nos viewsets de ListaMatriculaEstudante e ListaMatriculaCurso já estamos capturando a informação diretamente. Entretanto, para garantir que também haverá essa informação, colocaremos esse .orderBy() no queryset delas. Assim, caso precise ordenar, ela conseguirá capturar os dados ordenados.

class ListaMatriculaEstudante(generics.ListAPIView):
    def get_queryset(self):
        queryset = Matricula.objects.filter(estudante_id=self.kwargs['pk']).order_by("id")
        # Código omitido
        
class ListaMatriculaCurso(generics.ListAPIView):
    def get_queryset(self):
        queryset = Matricula.objects.filter(curso_id=self.kwargs['pk']).order_by("id")
        # Código omitido

Voltando ao terminal com "Ctrl+J", podemos confirmar que essa mensagem de aviso não está mais aparecendo. No navegador, fecharemos a guia da documentação do Django REST e acessaremos novamente a rota de estudantes na guia da aplicação. Recarregaremos a página para conseguir acessar.

Em seguida, se voltarmos ao terminal do VS Code, constataremos que foi possível acessar essa rota sem a mensagem de aviso anterior.

Próximos passos

Voltando ao Trello, verificaremos os outros pontos que precisam ser implementados na API. Após passar o cartão "Ordenação" para a coluna "FINALIZADO", trabalharemos na limitação das requisições de rota da API.

Limitando requisições - Limitando Requisições

Até o momento, podemos acessar qualquer rota da API quantas vezes quisermos, com a única condição de estarmos com o login feito. No entanto, essa quantidade ilimitada de acessos pode causar um problema para o sistema.

Vamos imaginar que várias pessoas estão tentando acessar esse sistema, mas não temos os recursos necessários para permitir que essa quantidade de pessoas acessem o sistema ao mesmo tempo, o que pode causar uma sobrecarga no servidor.

Além da sobrecarga, também temos que pensar no local em que esse sistema é hospedado. Se for em um serviço de nuvem, por exemplo, teremos recursos limitados, o que pode gerar um esgotamento ou até custos inesperados para essa quantidade de acesso.

Com essa falta de disponibilidade, o carregamento do site pode ficar lento ou o site pode "cair" (ficar fora do ar). Portanto, é importante implementar um limite de requisições para pessoas usuárias no sistema. Precisamos fazer isso agora.

Implementando o limite de requisições

Voltando ao Trello, na coluna "DESENVOLVENDO", abriremos o cartão "Limitar Requisições" que já verificamos. Ele nos informa algumas regras de API para pessoas usuárias logadas e anônimas.

Regras para a API:

> * 50 requisições por dia
> 
> * 20 requisições por dia

Regras específicas por rota:

No caso, precisamos limitar o acesso de pessoas usuárias a 50 requisições por dia apenas e o acesso de anônimos a 20 requisições por dia.

Verificaremos essas regras específicas posteriormente, mas, primeiro, precisamos saber como implementar isso globalmente para a API.

Em uma nova guia do navegador, acessaremos a documentação. Já vimos esse esquema, então, pesquisaremos "Django REST Framework" e abriremos o link da documentação do Django REST.

Django REST Framework

No topo dessa página, acessaremos o menu "API Guide" e, na lista suspensa, clicaremos na seção "Throttling".

Essa seção informa, em sua introdução, que o throttling é similar às permissions e determinará se uma requisição tem a permissão de ser autorizada ou não. Podemos traduzir permissions para restrições, pois ele restringe o acesso.

Para configurar o throttling, rolaremos a página para baixo e acessaremos a seção de configuração do throttling. Ela informa que devemos utilizar um esquema que usamos anteriormente: colocar as informações dentro do REST Framework no arquivo settings.py.

    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '100/day',
        'user': '1000/day'
    }

No código acima, disponível na documentação, temos informações tanto para pessoas usuárias anônimas quanto para pessoas usuárias logadas. Também temos que definir a quantidade de rates (acessos permitidos).

Ele informa, como exemplo, 100 acessos por dia para pessoas usuárias anônimas e 1.000 acessos por dia para pessoas usuárias logadas. Também informa que podemos definir essas restrições por segundo, minuto, hora e dia, de acordo com o que temos interesse e com o que o sistema solicitar.

Copiaremos o conteúdo acima e colaremos essas informações no settings.py. Abrindo o VS Code, pressionaremos "Ctrl+J" para fechar o terminal e "Ctrl+B" para abrir a aba lateral, na qual procuraremos o arquivo settings.py dentro da pasta "setup".

No interior desse arquivo, entre as chaves do REST_FRAMEWORK, acessaremos a última linha e adicionaremos uma vírgula para passar outra informação. Descendo uma linha, colaremos o código copiado.

Nesse código colado, precisamos modificar as informações para adicionar os dados solicitados para pessoas usuárias anônimas e logadas - 50 restrições por dia para pessoas usuárias logadas e apenas 20 para pessoas usuárias anônimas.

settings.py:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_PAGINATION_CLASS': rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 20,
    'DEFAULT_VERSIONING_CLASS': rest_framework.versioning.QueryParameterVersioning',
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '20/day',
        'user': '50/day'
    }
}

Também queremos entender como esse throttling está funcionando e atingindo esses pontos. Voltando à documentação aberta no navegador, acessaremos a seção "API Reference" para verificar o que são essas classes determinadas.

A subseção "AnonRateThrottle" informa que a classe anônima vai capturar pessoas usuárias não autenticadas pelo endereço de IP delas. Por isso, ele consegue identificar que uma pessoa usuária anônima, por exemplo, não conseguirá acessar em outro sites, porque estará utilizando no API ID.

Já a seção "UserRateThrottle" informa que uma chave será gerada para cada pessoa usuária autenticada, e por isso ele consegue identificar esses pontos.

Contudo, há um problema: para testar com pessoas usuárias anônimas, precisamos remover as autenticações primeiro. Além disso, há uma grande quantidade de volumes que podemos testar.

Como queremos verificar somente se esse código está funcionando, mudaremos as quantidades de restrições para 5 em pessoas usuárias logadas e 2 para anônimas.

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_PAGINATION_CLASS': rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 20,
    'DEFAULT_VERSIONING_CLASS': rest_framework.versioning.QueryParameterVersioning',
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '2/day',
        'user': '5/day'
    }
}

Testaremos para a pessoa usuária logada primeiro, que já temos.

Testando as restrições

Voltando à página da API REST no navegador, faremos o teste.

Ele considera as requisições a partir do momento que acessamos qualquer rota. Portanto, se acessarmos a rota /estudantes e retornarmos à página anterior cinco vezes, ele contará cinco acessos.

No momento que acessamos pela sexta vez e ultrapassamos o limite autorizado, não conseguimos mais verificar os dados API, e recebemos a mensagem de pedido limitado, informando que o próximo pedido poderá ser feito daqui a 86 mil segundos, calculados de acordo com o prazo que colocamos.

HTTP 429 Too Many Requests
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Retry-After: 86389
Vary: Accept

{
    "detail": "Pedido foi limitado. Expected available in 86389 seconds."
}

O teste de pessoa usuária logada está funcionando. Agora, verificaremos a pessoa usuária anônima.

Para verificar somente a situação de pessoas usuárias anônimas, voltaremos ao arquivo settings.py e comentaremos os blocos DEFAULT_AUTHENTICATION_CLASSES (de autenticação) e DEFAULT_PERMISSION_CLASSES (de permissão).

REST_FRAMEWORK = {
    #'DEFAULT_AUTHENTICATION_CLASSES': [
    #	'rest_framework.authentication.BasicAuthentication',
    # ],
    #'DEFAULT_PERMISSION_CLASSES': [
    #	'rest_framework.permissions.IsAuthenticated',
    # ],
    'DEFAULT_PAGINATION_CLASS': rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 20,
    'DEFAULT_VERSIONING_CLASS': rest_framework.versioning.QueryParameterVersioning',
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '2/day',
        'user': '5/day'
    }
}

Acessaremos novamente essa API, mas com um navegador anônimo. No Chrome, basta pressionar "Ctrl+Shift+N" para abrir uma janela anônima, na qual colocaremos o endereço dessa API na rota /estudantes.

Em seguida, carregaremos essa rota duas vezes, simulando dois acessos. Com apenas dois acessos, ele já mostra a mensagem de pedido limitado, informando o tempo que temos que esperar para a próxima requisição.

Por fim, voltando ao código, descomentaremos os blocos de autenticação e de permissão, e voltaremos os valores de throttling para os valores originais, 20 e 50.

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_PAGINATION_CLASS': rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 20,
    'DEFAULT_VERSIONING_CLASS': rest_framework.versioning.QueryParameterVersioning',
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '20/day',
        'user': '50/day'
    }
}

Com isso, conseguimos determinar globalmente a informação de limitar requisições. Podemos fechar o navegador.

Próximos passos

Se verificarmos o cartão que estamos trabalhando no Trello, temos regras específicas para cada rota. Para a matrícula, devemos ter 50 requisições por dia para pessoas usuárias logadas, mantendo a mesma regra, contudo, devemos ter apenas 5 requisições por dia para pessoas usuárias anônimas.

A seguir, teremos que personalizar essa limitação por rota específica.

Sobre o curso Django REST Framework: trabalhando com permissões, documentação, limitações, CORS e deploy na AWS

O curso Django REST Framework: trabalhando com permissões, documentação, limitações, CORS e deploy na AWS possui 110 minutos de vídeos, em um total de 48 atividades. Gostou? Conheça nossos outros cursos de Python em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Python acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas