Como Criar uma Aplicação Full-Stack com React 1/3
Criando a API com Node e Express
Fala galera, tudo certo? Então, fui tentar aprender React… Afinal de contas, já tinha visto tutoriais de Vue, até criei uma aplicação simples que consumia dados de uma API escrita em node e que estava funcionando legal. O que poderia dar errado não é mesmo?
Muita coisa deu errado e para ser bem sincero, foi uma das bibliotecas que mais demorei para aprender. No começo até achei meio ruim (minha zona de conforto gritando de saudades), mas disse para mim mesmo que continuaria e que mesmo não gostando de início, iria pelo menos fazer uma aplicação simples.
Então, após um tempo de leitura de artigos e tutoriais, muitos erros e acertos, horas em frente ao VS code tentando entender como que o código que eu tinha acabado de escrever funcionava, decidi por escrever um tutorial para criação de um app em React, desde a criação da API até a interface, pois, nada melhor para aprender do que ensinar não é mesmo?
Nesta série de tutoriais, vou guiar vocês na criação de uma To-do list. Indo desde a criação do servidor express que irá fazer conexão com o banco de dados MongoDB através do mongoose, até a criação das interfaces, utilizando React, Redux e um framework de css chamado bulma.
Bom, sem mais enrolação, bora lá começar.
Os outras duas partes:
Parte 2: Criando os componentes com React
Parte 3: Conexão com o servidor com Redux e Axios
Configurando o Ambiente de Desenvolvimento React
Para começarmos o desenvolvimento vamos digitar o comando npx create-react-app react-todo-bulma
, que irá criar uma pasta para nós com o nome de react-todo-bulma
e dentro dela, uma estrutura com o necessário para o início do desenvolvimento com React.
Após finalizar toda a instalação, vamos testar. Digite o seguinte comando.
cd react-todo-bulma
npm start
E agora, se tudo deu certo, você deve ter algo parecido com isto no seu navegador.
Pronto, você já tem uma aplicação React rodando :)
Criando o Servidor com Express e mLab
Nossa API ficará dentro de uma pasta /server
e dentro dela ficarão os arquivos responsáveis pela criação do servidor, assim como sua lógica e a conexão com o banco de dados.
Bora lá.
1. Estruturando a pasta
A primeira coisa a fazer é criar a estrutura de pastas digitando o comando abaixo na raiz do projeto.
mkdir server
cd server
mkdir config controllers models routes
- config: Arquivos relacionados a configuração do banco de dados.
- controllers: Definição das controllers que serão passadas para as rotas.
- models: Modelos do banco.
- routes: Definição dos endpoints da API.
Agora você deve ter uma estrutura igual a esta.
├── server/
│ ├── config/
│ ├── controllers/
│ ├── models/
│ ├── routes/
Esta é a estrutura que escolhi para este projeto, por se tratar de algo simples. Porém, para projetos mais complexo e escaláveis, recomendo adotar outro tipo de abordagem(isso vai de gosto pessoal).
Link para um discussão sobre os diferentes tipos:
https://gist.github.com/lancejpollard/1398757
2. Criando o servidor
Instale os seguintes pacotes.
npm install express body-parser --save
npm install nodemon --save-dev
- express é um framework que visa facilitar a criação de APIs utilizando node.
- body-parser é responsável por transformar a requisição do cliente em um objeto JSON e o tornar acessível através do req.body(vamos ver mais a frente).
nodemon é opcional, porém extremamente recomendado para desenvolvimento, já que qualquer alteração no código reinicia o servidor. Removendo a necessidade de fazer isso manualmente.
Caso não queira utilizar, para iniciar o servidor utilize o comandonode server.js
.
Agora, dentro da pasta server, crie um arquivo chamado server.js.
Com este arquivo definido, você já pode rodar a aplicação através do comando nodemon server.js
.
Se tudo correu bem, você deve ter o seguinte texto no terminal
Server listening on port 3001
Para facilitar, podemos adicionar o comando
"server": "nodemon server/server.js"
dentro dos scripts dopackage.json
. Ai é só digitar no terminalnpm run server
que ele irá funcionar normalmente.
3. Definindo o modelo
Vamos utilizar um framework chamado mongoose
, que facilita a conexão, criação de queries, criação de schemas e validação no MongoDB.
Para instalar o mongoose, digite npm install mongoose --save.
Agora, crie um arquivo dentro da pasta ./models
com o nome de Task.js.
Com este arquivo já temos om objeto que servirá de modelo para a criação de um documento, que no caso é a nossa Task
. É como se o que tivéssemos acabado de escrever fosse a planta de uma casa de um condomínio, e o que vamos criar serão as casas deste condomínio.
5. Criando as controllers
As controllers são as lógicas responsáveis pelas operações de entidade. Basicamente, vamos criar o CRUD de para a entidade Task
e enviar esta lógica através de um objeto para as nossas rotas.
Para as controllers, vamos exportar um objeto contendo todas as ações relacionadas à Task. Add Task, Get All Tasks, Delete Task e Update Task.
Vamos começar com o método add task
Aqui, atribuímos à variável task
um novo objeto do tipo Task
, passando para ele os atributos do body
da requisição. Depois salvamos este objeto com o comando task.save()
e através das promises nós retornamos ao cliente uma resposta.
O comando
then
só é executado caso o comandotask.save
dê certo, caso contrário é executado o métodocatch
.
Método get all tasks
O método find
pode receber como primeiro parâmetro uma query de busca, caso não receba, que é o caso acima, ele retorna todas as tasks.
Método get task by id
O método findById
recebe como primeiro parâmetro um id, retornando apenas a task com aquele id
específico.
Método delete task
Através do comando findByIdAndRemove
nós podemos pesquisar uma Task
apenas passando como parâmetro um id
e caso for encontrada a deletar.
Como vamos ver mais a frente, o id
é passado através da URL da API e por isso pôde ser acessado através do req.params
.
Método update task
Aqui utilizaremos o mesmo conceito do método para deletar uma Task, só que desta vez passaremos como segundo argumento o req.body
que irá conter toda a estrutura da Task
modificada e enviada pelo cliente.
No final, seu arquivo ./controllers/Task.js
deve estar como o seguinte
6. Definindo os endpoints
Endpoint basicamente é a URL de um site. Podemos definir que quando um endpoint for acessado a partir de um método HTTP especifico receberemos em nosso servidor uma requisição e executaremos uma ação relacionada ao tipo de requisição retornando ao usuário uma resposta.
Para criar as nossas endpoints, vamos utilizar a classe Router
do express
para facilitar seu desenvolvimento e gerenciamento. Como primeiro argumento, passaremos o endpoint que a URL deve ter para então executar a controller passada dentro do método HTTP. Com o código vai ficar mais fácil entender.
Dentro da pasta routes
crie um arquivo chamado Task.js
Aqui foram definidas duas rotas, cada uma com seus endpoints, seus métodos HTTP e seus respectivos controllers. A primeira rota será acessada quando a URL for igual à /
e poderá executar duas controllers, a de adição(add) e a de buscar todas as tasks(getAll) através dos métodos POST
e GET
respectivamente. Já a segunda rota, só será acessa quando houver um :id
após a /
.
Tá, mas o que é esse
:id
?
Isso é um parâmetro que a nossa rota aceita e chama de id
e que poderá ser acessado na aplicação através do atributo req.params.id
.
Pensando desta forma, se criássemos uma rota denominada /:taskId
acessaríamos ela através do atributo req.params.taskId.
Agora, para que nossa aplicação possa identificar e utilizar as rotas que definimos precisamos modificar pouca coisa no arquivo server.js
(sendo assim, vou ocultar o restante do código, para ficar mais objetivo).
Primeiro estamos importando o objeto Router
e atribuindo ele à variável TaskRoutes
. Depois utilizamos um comando do express que é o .use
e passamos dois argumentos, o primeiro é um caminho ‘base’ a ser utilizado e o segundo é um objeto da classe Router
. Com isso, estamos dizendo para a aplicação que para acessar as rotas definidas no objeto TaskRoutes
a URL precisa conter o caminho /api/tasks
.
Dessa forma, caso o usuário queira buscar todas as tasks ele precisará acessar a URL http://localhost:3001/api/tasks
e caso queira atualizar uma task especifica, precisará acessar http://localhost:3001/api/tasks/:id
. Esse padrão se aplicará a todas as rotas definidas dentro do arquivo ./routes/Task
.
Agora que já temos as rotas definidas e as controllers criadas, só precisamos de um banco de dados e é ai que entra o mLab.
5. Criando um banco de dados no mLab
mLab is the leading Database-as-a-Service for MongoDB, powering over half a million deployments worldwide.
Então basicamente, ele disponibiliza para você um banco de dados MongoDB na nuvem. E o melhor, eles possuem um plano grátis com 500 MB disponíveis.
Para começar a utilizar o serviço, é simples, basta entrar no site escolher o plano “free” e criar uma conta.
Após a criação da conta, é só criar uma nova instância de um banco de dados.
Ele então pedirá para você informar o provedor de cloud que você deseja utilizar, o tipo de plano, além da localização do servidor e o nome do banco.
Se tudo correu, bem você já tem um banco de dados rodando na nuvem :)
Agora precisamos cadastrar um usuário que terá acesso para manipulação do banco.
Ele vai pedir um nome de usuário e senha. Após a criação você deve ter algo parecido com isso.
Destacado em vermelho está a URI que iremos utilizar para conectar a API ao banco de dados.
Tudo pronto, agora só precisamos fazer as conexões e testes.
6. Conectando a API ao mLab
Agora vamos ao código que vai conectar a nossa API ao mLab.
Dentro da pasta /config
crie um arquivo chamado keys.config.js
Agora é só copiar a URI que foi criada para o nosso banco de dados e colocar no arquivo acima.
Próxima etapa é fazer a conexão propriamente dita, e para isso vamos utilizar o mongoose
.
Vamos editar o arquivo server.js
adicionando os comandos de conexão.
A primeira coisa que fizemos foi importar o mongoose e as configuração que havíamos definido. Logo depois, através do método mongoose.connect
passamos a mongodbUri do banco que criamos e basicamente já está feita a lógica da conexão.
Utilizamos then
e catch
apenas para termos informação no console sobre o sucesso ou erro de conexão.
Os comandos
useNewUrlParser: true
emongoose.set('useFindAndModify', false)
servem para que não apareça nenhuma mensagem deDepreciationWarning
no console.
O seu arquivo server.js
deve estar parecido com este
Para testar se está tudo funcionando, digite no terminal npm run server
ou nodemon server.js
. Caso tudo dê certo, você deve ter algo como
Server listening on port 3001
Database connected
Perfeito, agora nos resta o último passo, que é realizar os testes para validar as controllers.
7. Testando e finalizando
Para testar nossa API vou utilizar o Postman para enviar requisições e receber respostas da nossa API.
Após ter o Postman instalado, caso não esteja rodando, vamos iniciar nosso servidor através do comando npm run server
.
Agora com o Postman aberto, vamos digitar a URL http://localhost:3001/api/tasks
, definir o método como POST e colocar o seguinte na aba Body.
{
"title": "Tarefa 1",
"details": "Minha primeira tarefa",
}
Você deve ficar com algo parecido com isto. Ai é só apertar o botão Send.
E de resposta deve ter algo como
{
"completed": false,
"creation_date": "2018-10-03T02:20:38.865Z",
"_id": "5bb42926c2e08f3608207945",
"title": "Tarefa 1",
"details": "Minha primeira tarefa",
"__v": 0
}
Pronto, você já tem uma Task criada :D
Para vermos esta Task, vamos digitar alterar o método POST para GET e clicar em Send.
Se tudo correu bem, você agora deve ter uma lista contendo apenas uma Task.
[
{
"completed": false,
"creation_date": "2018-10-03T02:20:38.865Z",
"_id": "5bb42926c2e08f3608207945",
"title": "Tarefa 1",
"details": "Minha primeira tarefa",
"__v": 0
}
]
Agora, vamos alterar o detalhe desta Task. Para isso, mude o método GET para PUT, no lugar da URL coloque http://localhost:3001/api/tasks/_id
onde o _id
é o id da Task e no body
da requisição coloque o seguinte
{
"details": "Minha primeira tarefa foi criada e editada sucesso!!"
}
Agora é só clicar em Send e agora deve ter tido o retorno da Task de mesmo id só que com o campo details
modificado. Se sim, tudo funcionou como deveria.
Agora para testarmos a remoção, vamos alterar o método para DELETE e manter a mesma URL que utilizamos para atualizar e clicar em Send. E como retorno deve ter recebido o _id
da tarefa que foi excluída.
Você pode mudar o retorno da ação de exclusão, basta modificar a controller relacionada à ela.
Pronto, agora já temos uma API funcionando e salvando dados na nuvem. O próximo passo é desenvolver o cliente que vai consumir estes dados e para isso vamos utilizar React, Redux e o framework de css bulma. Mas isso fica para a próxima.
Vlw galera, Abs ✋