- Plataforma (não é uma linguagem)
- Permite usar Javascript no Back ends
- Não lida com eventos do usuário final
- Rotas e integrações
- gerenciador de pacotes
- instala bibliotecas de terceiros
- equiparável ao pip do Python
- Arquitetura Event-loop
- Call Stack (pilha de eventos)
- Last IN, First OUT (LIFO)
- Node single-thread (processo fica alocado em apenas um core do precessamento)
- C++ por trás com libuv
- Background threads
- Non-blocking I/O
- Não necessita dar toda a resposta de uma requisição de uma vez
- Dar uma resposta não gera perda de conexão como em outras linguagens
- Possibilita aplicações em tempo real
- ExpressJS como base
- sem opinião
- não possui uma estrutura fechada
- ótimo para iniciar
- microframework
- micro-serviços
- possibilita dividir a aplicação
- sem opinião
- AdonisJS
- NestJS
- do tipo requisição e resposta
- requisição feita por um cliente
- resposta retorna através de uma estrutura de dados
- cliente recebe resposta e processa resultado
- GET
- POST
- PUT
- DELETE
- múltiplos clientes front-end e até mesmo back-end
- protocolo de comunicação padronizado
- mesma estrutura para web / mobile / API pública
- comunicação com serviços externos
- JavaScript Object Notation
- objetos que podem contem arrays e outros objetos
-
GET:
- utiliza Query Params
- vai na própria URL
- inicia-se após o nome do recurso, com o sinal de interrogação ?
http://api.com/company/1/users?page=2
-
POST:
- utiliza-se Body para não poluir a URL e não mostrar campos sensíveis
{ "user": { "name": "Arlucio Nunes", "email": "arlucionunes@gmail.com", "techs": ["ReactJS", "NodeJS", "Reactive Native"] } }
- 1xx: Informational
- 2xx: Success
- 200: SUCCESS
- 201: CREATED
- 3xx: Redirection
- 301: MOVED PERMANENTLY
- 302: MOVED
- 4xx: Client Error
- 400: BAD REQUEST
- 401: UNAUTHORIZED
- 404: NOT FOUND
- 5xx: Server Error
- 500: INTERNAL SERVER ERROR
- criar uma pasta
mkdir nome_da_pasta
- iniciar um projeto javascript
yarn init -y
- abrir pasta com o VScode
code .
- criar uma pasta src no vscode
- criar um arquivo index.js
- importar uma dependência, express: é um microframework
yarn add express
- criar uma aplicação
const express = require('express');
const app = express();
- necessário ouvir uma porta
- acessar via localhost: porta (qualquer porta acima de 80)
- bastante utilizado 3333 e acima, caso tenha mais aplicações node
app.listen(3333)
- fazer o express monitorar a rota e retornar uma resposta
app.get('/projects', (request, response) => {
return response.send('Hello World');
});
- executando a aplicação
node src/index.js
- ir no navegador e buscar endereço localhost:3333/projects
- não é necessário ir para um endereço como no exemplo projects. Pode ser usado apenas "/", então será acessado direto o localhost:3333
- retornando dados do tipo JSON
app.get('/', (resquest, response) => {
return response.json({message: 'Hello World'});
});
- o node não faz a reinicialização automática do servidor quando há uma alteração, portanto é necessário CTRL + C, para cancelar a execução e executá-lo de novo.
- ferramenta usada por toda comunidade node
- atualização automática do servidor, toda vez que o node detecta uma alteração
yarn add nodemon -D
- executando...
yarn nodemon src/index.js
- criando atalho para execução
- no arquivo package.json
"main": "src/index.js",
"scripts": {
"dev": "nodemon"
},
- alterar o método app.listen, que pode receber uma função como segundo parâmetro
app.listen(3333, () => {
console.log('=> Back-end started!');
});
- buscar informações do back-end
- rota usada para retornar alguma informação
⇒ Nem toda rota retorna uma informação. Se o usuário for deletar alguma coisa do back-end, por exemplo, essa ação não retornará uma informação.
- criar uma informação no back-end
- alterar uma informação no back-end
- ambos atualizam informações
- put serve para atualizar um recurso por completo
- Ex: usuário altera todos os dados do seu perfil na aplicação de uma vez
- patch serve para atualizar uma informação específica
- Ex: alterar a foto de avatar do usuário
- deleta uma informação no back-end
- programa baixado em insomnia.rest automaticamente
- instalado tema dracula automático também
- criar uma pasta para requisições do mesmo recurso
- no caso criaremos uma folder chamada Projects
- adicionamos novas requests
- damos um nome. Ex: List
- escolhemos o método. Ex: Get
- depois colocamos o caminho da rota
- clicar em Send para finalmente testar a rota
⇒ Lembrando que para as rotas put e delete, deve-se colocar um /id depois do caminho
- serve para criar atalhos que são muito usados
- Manage Environments
- adicionar um novo sub environment
- colocar um nome
- adicionar uma cor
- colocar um código padrão json, Ex:
{
"base_url": "http://localhost:3333"
}
- clicar em Done
- selecionamos o Environment desejado
- alteramos o caminho da rota e adicionamos o objeto criado com o código
- Ctrl + Espaço
- selecionar base_url
- manter o caminho restante do recurso /projects
⇒ Lembrando que para as rotas put e delete, deve-se colocar um /id depois do caminho
*Parâmetros: Formas do Front-end enviar algum tipo de informação
-
usado principalmente para filtros e paginação
-
enviar parâmetros Query:
- adicionar um ponto de interrogação ? após o recurso
- nome_do_parâmetro=valor_do_parâmetro
- para adicionar mais parâmetros, usar o 'E' comercial &
- Ex:
http://localhost:3333/projects?title=React&owner=Elton
-
no Insomnia pode ser usado a aba Query
-
no código da aplicação adicionamos:
const query = request.query;
console.log(query);
- que deverá retornar:
{ title: 'React', owner: 'Elton' }
- desmembrando a variável query, podemos deixar da seguinte forma:
const {title, owner} = request.query;
console.log(title);
console.log(owner);
- que deverá retornar:
React
Elton
- identificar recursos na hora de Atualizar/Deletar
- solicitamos com o identificador depois do caminho e identificamos no código conforme a seguir, respectivamente:
http://localhost:3333/projects/1
app.put('/projects/:id', (request, response) => {...
- para nosso back-end identificar o id adicionamos ao código:
const params = request.params;
console.log(params);
- que deverá retornar:
{ id: '1' }
- da mesma forma que na Query, podemos desestruturar conforme a seguir:
const {id} = request.params;
console.log(id);
-
conteúdo na hora de criar ou editar um recurso
-
esse conteúdo, ou seja, essas informações, chegam para o front-end através de JSON
-
na requisição feita pelo Insomnia
- no campo Body, selecionar JSON
- criar um objeto com as informações desejadas. Ex:
{ "title": "Aplicativo React Native", "owner": "Elton Possidonio" }
-
no código da aplicação:
const body = request.body;
console.log(body);
- para o Express interpretar a requisição acima:
app.use(express.json());
- retornando então:
{ title: 'Aplicativo React Native', owner: 'Elton Possidonio' }
- desmembrando mais uma vez:
const {title, owner} = request.body;
console.log(title);
console.log(owner);
- retornando:
Aplicativo React Native
Elton Possidonio
- criar API, armazenando projetos
- listar
- criar
- deletar
- por enquanto sem uso de Banco de Dados
- criar uma variável projects, antes das rotas, que vai ser um array vazio
const projects = [];
- fechando / reiniciando a aplicação, a variável retorna para o valor dela, que é um array vazio
- rota após deixar os filtros comentados e retornar o array
app.get('/projects', (request, response) => {
// const {title, owner} = request.query;
// console.log(title);
// console.log(owner);
return response.json(projects);
});
- apago os console logs da rota post onde foram marcados como comentário
app.post('/projects', (request, response) => {
const {title, owner} = request.body;
/*
console.log(title);
console.log(owner);
*/
return response.json([
'Projeto 1',
'Projeto 2',
'Projeto 3',
])
})
- criar uma variável que contenha um title, um owner e um id
- para a criação do id, instalar uma biblioteca chamada uuidv4
yarn add uuidv4
- importar apenas a função uuid do módulo uuidv4
const { uuid } = require('uuidv4');
- criando a variável project, conforme descrito acima
const project = { id: uuid(), title, owner };
- criar um push, que irá enviar o que foi criado para o array
projects.push(project);
- retornar o projeto que foi criado
return response.json(project);
- ao rodar no Insomnia
DeprecationWarning: uuidv4() is deprecated. Use v4() from the uuid module instead.
- como a biblioteca uuidv4 está defasada, foi instalada a biblioteca uuid e usada a função v4, conforme orientação da notificação, ficando os comandos e códigos da seguinte forma:
yarn add uuid // para instalar o módulo
const { v4 } = require('uuid'); // para importar universal unique id
const project = { id: v4(), title, owner }; // usando a função na variável
- a rota GET deve estar vazia, caso tenha reiniciado a aplicação
- na rota POST, dando um Send com o que já estava criado anteriormente
- deve gerar uma resposta do tipo
Repare no id único gerado. Caso aperte Send novamente, será criado um projeto, apenas com o id único diferente
- nessa rota, repare que recebo um id como parâmetro
app.put('/projects/:id', (request, response) => {
const {id} = request.params; // aqui recebo id como parâmetro
console.log(id);
return response.json([
'Projeto 4',
'Projeto 2',
'Projeto 3',
])
})
- percorremos então o array projects, em busca do projeto que queremos atualizar, utilizando a função find() do JS
const project = projects.find(project => project.id === id);
- porém, para facilitar a atualização, procuramos a posição do projeto no array, ou seja, o índice:
const projectIndex = projects.findIndex(project => project.id === id);
- colocamos uma condição também caso não encontremos o projeto
if (projectIndex < 0) { // caso não encontre, retorna uma resposta -1
return response.json({ error: 'Project not found.' })
}
- testando a rota PUT no Insomnia:
repare que retornou um status code de sucesso 200
- para setar esse status code mudamos o código para:
return response.status(400).json({ error: 'Project not found.' })
- retornando a resposta:
- com o projeto encontrado, criamos uma nova informação do projeto
- pegamos a informação de dentro do body
const { title, owner } = request.body;
- recriamos o projeto
const project = {
id,
title,
owner,
}
- substituímos no array na mesma posição
projects[projectIndex] = projects;
- retornamos o projeto atualizado
return response.json(project);
- código final
app.put('/projects/:id', (request, response) => {
const { id } = request.params;
const { title, owner } = request.body;
const projectIndex = projects.findIndex(project => project.id === id);
if (projectIndex < 0) { // caso não encontre, retorna uma resposta -1
return response.status(400).json({ error: 'Project not found.' })
}
const project = {
id,
title,
owner,
}
projects[projectIndex] = projects;
return response.json(project);
})
- em Post, criamos um projeto e copiamos o seu id
- em Put, colocamos o id do projeto após projects
- copiamos o conteúdo da rota de criação em Post
- colamos em Put, selecionamos o formato json, alteramos alguma coisa e damos um send
- podemos encontrar o projeto na rota de List
- identificamos o id do projeto com base no parâmetro passado na URL
- localizamos dentro do array
- caso ele exista, utilizamos a função splice(), que retira uma informação de dentro de um array, passando como parâmetro o índice e quantas posições quero remover a partir desse índice, no caso apenas a informação contida nele, então no caso 1
projects.splice(projectIndex, 1);
- nesse caso retornamos apenas um valor em branco, usando o send()
- recomenda-se enviar com o status code 204, quando for uma resposta vazia
return response.status(204).send();
- basta copiar o id, colocar na URL após projects e apertar send
- voltado na listagem, não se encontra mais o projeto
- utilizando apenas filtro title, com valor React, por exemplo
- será encontrado todos os projetos que o título contenha React
- criamos uma constante chama results, observando se o título foi preenchido pelo usuário
- caso tenha sido preenchido
- usamos função filter() e includes()
- caso não tenha sido preenchido, retorna todos os projetos
- código final:
app.get('/projects', (request, response) => {
const { title } = request.query;
const results = title
? projects.filter(project => project.title.includes(title))
: projects;
return response.json(results);
});
- criando 2 projetos e desabilitando o filtro e buscando em List
- habilitando o filtro em Query
- resultado:
- interceptador de requisições
- interrompe totalmente a requisição
- altera dados da requisição
- formato do tipo função nome (requisição. resposta)
- terceiro parâmetro next
- pega como requisição:
- querys
- bodys
- params
- quando queremos que algum trecho de código seja disparado de forma automática em uma ou mais rotas da aplicação
- criaremos e chamaremos a função para sabermos qual rota está sendo chamada no Insominia
function logRequests(request, response, next) {
const { method, url } = request
const logLabel = `[${method.toUpperCase()}] ${url}`;
console.log(logLabel);
}
app.use(logRequests);
- chamando a rota GET no Insomnia
- caso a função next não seja chamada no final do middleware, o próximo middleware, ou seja, a rota não será disparada
- para o interceptador não interromper o restante do fluxo da aplicação é necessário chamar a função next
function logRequests(request, response, next) {
const { method, url } = request
const logLabel = `[${method.toUpperCase()}] ${url}`;
console.log(logLabel);
return next(); // Próximo middleware
}
- os middlewares também podem ser aplicados em uma rota específica
- primeiro comentamos onde ela está sendo chamada
// app.use(logRequests)
- inserimos a função dentro da rota desejada
app.get('/projects', logRequests, (request, response) => {
const { title } = request.query;
const results = title
? projects.filter(project => project.title.includes(title))
: projects;
return response.json(results);
});
- o express permite que depois do next() seja executado outro comando
- nesse caso será executado o middleware, a rota e depois esse comando
- para que o comando depois do next() seja acessível, é necessário tirar o return
- com isso podemos, utilizando o comando console.time e console.timeEnd, saber o tempo da requisição
function logRequests(request, response, next) {
const { method, url } = request
const logLabel = `[${method.toUpperCase()}] ${url}`;
console.time(logLabel);
next(); // Próximo middleware
console.timeEnd(logLabel)
}
- os middlewares também podem ser usados para validação
- verifica se o dado que o usuário está enviando está no formato correto
- nessa função será verificado o id das rotas PUT e DELETE
- primeiramente importamos uma função de verificação do módulo uuid, chamada validate
const { v4, validate } = require('uuid'); // importa universal unique id
- criamos a função de validação
function validateProjectId(request, response, next) {
const { id } = request.params;
if (!validate(id)) {
return response.status(400).json({ error: 'Invalid project ID.' });
}
return next();
}
- note que a requisição será interrompida, caso a requisição não seja validada
- depois podemos inserir a função dentro da rota desejada
app.put('/projects/:id', validateProjectId, (request, response) => ...
- fazendo uma requisição inválida pelo Insomnia
- pode-se também, utilizando a app.use(), chamar a função apenas para as rotas desejadas
app.use('/projects/:id', validateProjectId);
- nesse caso, apenas as rotas PUT e GET, que trabalham com essa requisição que usa o id, serão validadas pela função