Construindo uma aplicação simples usando Nuxt.js/Vue.js e Django — Parte I
Django é o framework de desenvolvimento web Python mais popular. Recentemente, ele tem sido amplamente utilizado para desenvolver plataformas de backend, fornecendo acesso a dados via REST, GraphQL ou tecnologias similares. Embora muitos artigos tenham sido escrito com o objetivo de mostrar a integração do Django como backend com frameworks de frontend Javascript, como o React, Angular, VueJS, eu não encontrei um artigo completo que apresente a integração do Django com o NuxtJS, incluindo o gerenciamento de requisições autenticadas.
Eu gostaria de frisar que muitas outras estratégias poderiam ser empregadas para desenvolver tal integração, mas eu apresento a que se parece, ao meu ver, uma das mais adequadas. Eu implemento o backend usando Django 3 com Django REST framework para construir as APIs. O frontend é implementado com NuxtJS consumindo e renderizando as respostas JSON oriundas da API Django REST.
O problema
Nesta nossa primeira parte, nós criamos um backend usando Django com o Django REST Framework( DRF). Tal backend fornece apenas o módulo de autenticação, usando o pacote simple JWT. O frontend, construído usando NuxtJS, consome tal API, sendo que os usuários são capazes the acessar a API usando seus respectivos ‘usuário’ e ‘senha’.
A implementação do Backend
Eu sugiro usar o Poetry para gerenciar os pacotes Python na solução backend. Uma forma de instalar o poetry é usando o pip, embora outras formas podem ser encontradas na página do projeto.
Inicialmente, vamos instalar o poetry:
$ pip install --user poetry
$ echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
Criando o ambiente virtual
No restante do artigo, eu considero que você esteja desenvolvendo a solução em um diretório chamado django-nuxt-project
. Qualquer outro nome de diretório e caminho pode ser usado. No diretório do projeto,é necessário criar o arquivo de projeto do poetry.
$ poetry init
O comando ‘init’ criará o arquivo pyproject.toml
, que contém as dependências do projeto. A caixa a seguir apresenta uma lista-exemplo de respostas:
Package name: projeto-django-nuxt
Version: 1.0.0
Description: Um projeto simples de integração Django-Nuxt .
Author: Eduardo da Silva
License:
Compatible Python versions [^3.6]:
Would you like to define your main dependencies interactively: no
Would you like to define your dev dependencies (require-dev) interactively: no
Do you confirm generation: yes
Após criar o arquivo pyproject.toml
, é necessário criar o ambiente virtual para esse projeto.
$ poetry install
O comando ‘install’ cria o novo ambiente no diretório ~/.cache/pypoetry/virtualenvs
. Em seguida, você pode ativar o ambiente virtual executando o seguinte comando no diretório do projeto:
$ poetry shell
Instalando o Django
Agora, é necessário adicionar o Django ao projeto Poetry.
É importante enfatizar que os próximos comandos são executados dentro do ambiente do poetry, criado anteriormente.
$ poetry add django
O comando ‘add’, como se supõe, adiciona a última versão do Django ao ambiente poetry corrente. Agora, vamos criar nosso projeto Django de backend, com o seguinte comando:
$ django-admin startproject backend .
Observe que o último ponto (.) do comando apresentado garante que o Django não crie um novo diretório para o novo projeto. Então, o arquivo manage.py
estará localizado no diretório raiz do projeto.
Em nosso ambiente, usaremos o SQLite como gerenciador de banco de dados. Assim, nenhum modificação adicional será necessária, por enquanto, no arquivosettings.py
. Em seguida, nós devemos gerar o arquivo de banco de dados e criar um novo superusuário para gerenciar o projeto backend.
$ ./manage.py migrate
$ ./manage.py createsuperuserUsername (leave blank to use 'seu usuário'): admin
Email address: admin@exemplo.com
Password: ********
Password (again): ********
Para testar nossa nova instalação, nós podemos executar o projeto Django atual:
$ ./manage.py runserver
Assim, nós podemos acessar via um navegador a URL http://localhost:8000
. A seguinte página padrão do Django será apresentada.
Finalmente, nós inicializaremos uma aplicação em nosso projeto. Consideraremos apenas uma aplicação, chamado ‘core’, que gerenciará os models, serializers, e views. Os comandos a seguir criam a nossa aplicação:
$ mkdir backend/core
$ ./manage.py startapp core backend/core
Instalação dos pacotes necessários
Em geral, um sistema crescerá passo-a-passo, e novos pacotes serão adicionados ao projeto sempre que necessário. Em nosso exemplo, decidimos adicionar todos os pacotes necessários no início, a fim de evitar grandes alterações nos arquivos de configurações.
Em nosso exemplo, os seguintes pacotes serão utilizados no ambiente de backend:
+ djangorestframework
+ djangorestframework-simplejwt
+ django-environ
+ django-cors-headers
Quando eu criei esse tutorial, o pacote djangorestframework-simplejwt requer o Python ≥ 3.6 e ≤ 3.9. Ao criar o arquivo pyproject.toml
(o arquivo de projeto do Poetry) você será questionado pela versão do Python. Se você escolher a versão padrão, a versão do Python será configurada como ^3.8.
Dessa forma, é necessário alterar o arquivo pyproject.toml
, como mostra o código a seguir, e alterar essa informação (linha 8):
Por fim, para adicionar tais pacotes, nós executamos os seguintes comandos no diretório do projeto:
$ poetry add djangorestframework
$ poetry add djangorestframework-simplejwt
$ poetry add django-cors-headers
O arquivo settings.py
Agora, alteraremos o arquivo settings.py
, que contém as configurações gerais do projeto Django. Aqui, colocamos a versão final desse arquivo. Também, foram adicionadas as novas informações, mantendo o conteúdo padrão do arquivo, excluindo os comentários.
As principais alterações são listadas abaixo:
- linhas 18–19: novos apps instalados, respectivamente, o rest_framework e o core.
- linha 23: adicionar o middleware corsheaders, que permite que os recursos sejam acessados em outros hospedeiros ou domínios.
- linhas 60–65: configurações relacionadas ao simplejwt, o JSON Web Token authentication plugin para o Django REST Framework.
- linha 67: também relacionada com o middleware corsheader.
- linhas 78–83: correspondente às configurações do rest_framework. Também incluem o modelo de permissões considerado no projeto, que é o DjangoModelPermissions (linha 82).
A autenticação
Agora, nós configuramos o projeto backend para gerenciar as autenticações. Como nós já temos o pacote restframework_simplejwt
, nós precisamos apenas adicionar o caminho das URLs no projeto.
Para isso, editamos o arquivo backend/urls.py
como segue:
Observe que as linhas 7–8 correspondem às rotas de autenticação. A URL api/token
requer os campos username e password, e é responsável por autenticar os usuários. Se o usuário e senha estão corretos, o usuário será autenticado e um token será enviado via JSON. Porém, se o usuário ou a senha estiverem errados, uma mensagem de erro será retornada.
A URL api/refresh_token
é responsável por atualizar o token do usuário, quando o atual estiver expirado.
A implementação do frontend
Para instalar o nuxtJS, o pacote npx é necessário. Se você já tem o npm instalado, apenas execute o seguinte comando:
$ npm install -g npx
Criando o projeto
Para criar um novo projeto Nuxt, use o seguinte comando, considerando que ‘frontend’ é o nome do seu novo projeto:
$ npx create-nuxt-app frontend
As seguintes questões serão perguntadas. Os valores em parênteses são os padrões:
Project name: frontend
Project Description: Uma integração Django-Nuxt - frontend.
Author Name: Eduardo da Silva
Choose programming language: JavaScript
Choose the package manager: Npm
Choose UI framework: Buefy
Choose custom server framework: None
Choose Nuxt.js modules: Axios
Choose linting tools: ESLint, Prettier
Choose test framework: None
Choose rendering mode: Universal (SSR)
Choose development tools: jsconfig.json
Com isso, a versão inicial do projeto estará disponível no diretório frontend/
. Para executar, digite:
$ cd frontend
$ npm run dev
A versão frontend estará escutando no endereço http://localhost:3000, como apresentado a seguir:
Alterações iniciais
A primeira coisa a fazer é remover os cartões de exemplo da página inicial e o item ‘Inspire’ do menu lateral. Para remover os cartões da página inicial, edite o arquivo frontend/pages/index.vue:
Então, para remover o item ‘Inspire’ do menu lateral, edite o arquivo frontend/layouts/default.vue
(alterações após a linha 49):
Obs: no meu ambiente de desenvolvimento, eu modifiquei o arquivo de configuração do prettier, para considerar linhas com 80 caracteres. Assim, eu precisei alterar o
frontend/.prettierc
(adicionada a linha 5):
Adicionando autenticação ao frontend
Inicialmente, adicionamos o módulo nuxt-auth ao projeto. Mas, antes disso, é necessário ativar o módulo vuex-store. Como o nosso projeto ainda não tem o vuex-store ativado, é necessário criar um arquivo vazio frontend/store/index.js
. Então, instale o módulo nuxt-auth, como segue:
$ npm install @nuxtjs/auth
Também, sugiro usar o pacote toast, para mostrar mensagens de informações ao usuário. O seguinte comando pode ser utilizado:
$ npm install @nuxtjs/toast
Em seguida, nós devemos editar o arquivo frontend/nuxt.config.js
, adicionando o seguinte:
...
modules: [
‘nuxt-buefy’,
‘@nuxtjs/axios’,
‘@nuxtjs/auth’,
‘@nuxtjs/toast’
],
auth: {
strategies: {
local: {
endpoints: {
login: {
url: '/api/token/',
method: 'post',
propertyName: 'access',
altProperty: 'refresh'
},
logout: {},
user: false
}
}
},
redirect: {
login: '/login',
},
},
router: {
middleware: ['auth']
},
axios: {
baseURL: 'http://localhost:8000'
},
toast: {
position: 'top-center',
iconPack: 'fontawesome',
duration: 3000,
register: [
{
name: 'defaultSuccess',
message: (payload) =>
!payload.msg ? 'Operação bem sucedida' : payload.msg,
options: {
type: 'success',
icon: 'check'
}
},
{
name: 'defaultError',
message: (payload) =>
!payload.msg ? 'Oops.. Erro inesperado' : payload.msg,
options: {
type: 'error',
icon: 'times'
}
}
]
},...
A versão final do arquivo nuxt.config.js
está apresentada abaixo:
A autenticação é configurada nas linhas 25 e 26–47.
- Linha 25: corresponde ao módulo nuxtjs-auth.
- Linhas 26–44: as configurações do módulo auth. Primeiro definimos como ‘local’ a estratégia de autenticação, informando que a página de login estará localizada na rota
/login
. Observe que a linha 31 é relativa a baseURL do axios (definida na linha 49). - Linha 46: garante que todas as páginas acessadas devem estar autenticadas. Se um usuário não está autenticado, ele será redirecionado à página de login (linha 40).
- Lines 46–48: correspondem às informações básicas do módulo Axios.
Também, as linhas 49–73 são relacionadas ao módulo toast, responsável por mostrar mensagens aos usuários. Configuramos dois tipos de mensagens: defaultSuccess e defaultError.
Agora, devemos criar as páginas de login e logout. Ambas estarão localizadas no diretório frontend/pages.
Primeiramente, a página de login:
As linhas 1–14 apresentam o código correspondente ao formulário de login, que contém dois campos, username e password. Ambos os campos são armazenados em um objeto chamado user
. Finalmente, os formulário tem um botão Login, cujo evento onclick será direcionado ao método login().
O método login() é apresentado nas linhas lines 24–37, em que o método loginWith()
(do pacote nuxtjs-auth) é invocado com as informações do objeto user
.
Agora, para finalizar nosso exemplo, a página de logout (frontend/pages/logout.vue
).
Nesse componente Vue, nós definimos apenas o método created que executa o logout usando um método predefinido do pacote nuxt-auth (linha 8). Após o logout, o usuário será direcionado para a página raiz (/).
Para testar o método de logout, nós podemos adicionar um item logout ao menu lateral, que será apresentado quando o usuário estiver autenticado. Para isso, edite o arquivo frontend/layout/default.vue:
Quando comparado com a versão anterior do arquivo default.vue
, algumas alterações foram realizadas. Inicialmente, criamos duas listas (linhas 54–97), chamadas globalItems
e authenticatedItems
. Essas listas contém itens que são apresentados no menu lateral. A primeira lista, globalItems
, contém os itens apresentados a todos os usuários (autenticados ou não). Por outro lado, a lista authenticatedItems
contém apenas os itens apresentados aos usuários autenticados.
A interpolação dessas listas na página é implementada nas linhas 25–38. Observe que o código possui dois laços v-for. O primeiro percorre globalItems
, enquanto que o segundo percorre authenticatedItems
. Contudo, o segundo laço v-for está dentro de uma tag <span>
, que é visível apenas quando a variável loggedIn
for verdadeira.
Mas quem controla essa variável loggedIn
? Ela é fornecida via o módulo vuex-store. Na linha 50, importamos o método mapState do módulo vuex. Então, nas linhas 70–72, definimos um dado computado, que mapeia a variável loggedIn do módulo de armazenamento ‘auth’ para o dado computado local loggedIn.
Na parte dois, nós implementaremos os models, serializers, e views no Django, e como consumir tais dados usando o NuxtJS.
Bom proveito!