Skip to content

Conhecendo conceitos de back-end com Node.JS, algumas ferramentas e frameworks

Notifications You must be signed in to change notification settings

eltonrp/backend_com_node

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Node.js

Conceitos gerais

  • Plataforma (não é uma linguagem)
  • Permite usar Javascript no Back ends
    • Não lida com eventos do usuário final
    • Rotas e integrações

O que é npm/yarn?

  • gerenciador de pacotes
  • instala bibliotecas de terceiros
  • equiparável ao pip do Python

Características

  • 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

Frameworks

  • ExpressJS como base
    • sem opinião
      • não possui uma estrutura fechada
    • ótimo para iniciar
      • microframework
    • micro-serviços
      • possibilita dividir a aplicação

Frameworks opinados

  • AdonisJS
  • NestJS

Conceitos API Rest

Funcionamento

  • 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

As rotas utilizam métodos HTTP

  • GET
  • POST
  • PUT
  • DELETE

Benefíficos

  • 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

JSON

  • JavaScript Object Notation
  • objetos que podem contem arrays e outros objetos

Alguns tipos de Requisições

  • 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"]
    	}
    }

HTTP Codes

  • 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

Criando Projeto Node

  • 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();

Acessar a aplicação pelo navegador

  • 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.

Configurando Node

Instalação Nodemon

  • 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"
  },

Retornando um feedback no terminal sobre a aplicação

  • alterar o método app.listen, que pode receber uma função como segundo parâmetro
app.listen(3333, () => {
	console.log('=> Back-end started!');
});

Métodos HTTP

Get

  • 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.

Post

  • criar uma informação no back-end

Put/Patch

  • 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

Delete

  • deleta uma informação no back-end

Utilizando o Insomnia

  • 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

Adicionando um environment

  • 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


Tipos de Parâmetros

*Parâmetros: Formas do Front-end enviar algum tipo de informação

Query Params

  • 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

Route Params

  • 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);

Request Body

  • 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

Aplicação Funcional

  • 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 de listagem de projetos GET

  • 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);
});

Rota de criação dos projetos POST

  • 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

No Insomnia

  • 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

Rota de update PUT

  • 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:

Atualizando o projeto

  • 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);
})

Testando no Insomnia

  • 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

Rota de Delete

  • 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();

Testando no Insomnia

  • basta copiar o id, colocar na URL após projects e apertar send

  • voltado na listagem, não se encontra mais o projeto

Filtrando Rota List

  • 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);
});

Testando no Insomnia

  • criando 2 projetos e desabilitando o filtro e buscando em List

  • habilitando o filtro em Query

  • resultado:


Middlewares

  • 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

Utilização

  • 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);
});

Outra utilização dos middlewares

  • 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)
}

Criando um middleware de validação

  • 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

About

Conhecendo conceitos de back-end com Node.JS, algumas ferramentas e frameworks

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published