Programação
Web
Prof. Alan Ferreira dos Santos
AVANÇADA
Alan Ferreira dos Santos
Formado pelo Centro Universitário Integrado (2010)
Convertido para Web e trabalhando nisso desde 2011
Metodologias Ágeis - Node.js - Vue.js - PHP - React Native
alanfsantos
Câmera Aberta
Detalhes
Disciplina
da
Objetivo Geral
Desenvolver aplicações web utilizando linguagens de programação que são processadas no servidor.
Objetivos Específicos
Distinguir a diferença entre front-end e back-end;
Entender o padrão arquitetural MVC;
Entender os padrões arquiteturais REST e RESTfull;
Estruturar uma API;
Utilizar a linguagem de programação Node.js e seus frameworks;
Integrar aplicações web com banco de dados;
Desenvolver testes para aplicações web no back-end.
Processo
Avaliação
de
Avaliação
A avaliação da aprendizagem terá caráter semestral e será realizada por meio de avaliações do 1º e 2º bimestres.
A avaliação de cada bimestre será composta por avaliação somativa com valor de 7,0 pontos, distribuídos em 4,0 pontos de prova teórica e 3,0 pontos de prova prática; e avaliação continuada, no valor de 3,0 pontos, incluindo neste último componente a nota referente às atividades práticas supervisionadas.
Nota Semestral
A nota semestral será calculada a partir de média aritmética simples das notas do 1º e 2º bimestres. Será considerado aprovado o aluno que obtiver média semestral igual ou superior a 7,0 pontos, com frequência mínima de 75% nas aulas.
Exame
Terá direito a Exame Final da disciplina o aluno com média entre 4,0 e 6,99 e frequência mínima de 75% nas aulas. A nota para aprovação no Exame Final deverá ser igual ou superior a 6,0.
Plano de Ensino
Quiz
https://qrgo.page.link/rE72B
Front-end
VS
Back-end
Front-end
-
Camada visual de uma aplicação web;
-
Recursos do navegador;
-
HTML, CSS e JavaScript;
-
Conteúdo Estático.
Back-end
-
Camada de negócio;
-
Processamento no servidor;
-
Comunicação com Banco de dados;
-
Validações e garantias de que o usuário final não manipulará as informações;
-
PHP, Node.js, Java, etc.;
-
Conteúdo Dinâmico.
Padrões
Arquiteturais
Padrões Arquiteturais
Melhoram o particionamento e promove reuso de design fornecendo soluções para problemas recorrentes.
MVC
MVC
Separa sua aplicação em 3 camadas.
A camada de interação do usuário(view), a camada de manipulação dos dados(model) e a camada de controle(controller).
REST
REST
Sigla de Representational State Transfer, e tem como objetivo primário a definição de características fundamentais para a construção de aplicações Web seguindo boas práticas.
HTTP
Hypertext Transfer Protocol é um o protocolo de transferência de dados base da Web.
Métodos
GET
O método GET é utilizado quando existe a necessidade de se obter um recurso. Ao executar o método GET sob um recurso, uma representação será devolvida pelo servidor.
Em aplicações Web, normalmente é retornado uma representação HTML.
POST
Utilizamos o método POST quando desejamos criar algum recurso no servidor a partir de uma determinada representação. Exemplo disso é quando fazemos a submissão de algum formulário em uma página Web.
PUT
Semelhante ao método POST, a ideia básica do método PUT é permitir a atualização de um recuso no servidor.
DELETE
O método DELETE é utilizado com o intuito de remover um recurso em um determinado servidor.
Respostas
-
1XX – Informações Gerais
-
2XX – Sucesso
-
3XX – Redirecionamento
-
4XX – Erro no cliente
-
5XX – Erro no servidor.
RESTful
RESTful
Chamamos de RESTful o sistema que aplica os conceitos REST.
API
API
Provém do inglês Application Programming Interface, trata-se de um conjunto de rotinas e padrões estabelecidos e documentados por uma aplicação A, para que outras aplicações consigam utilizar as funcionalidades desta aplicação A, sem precisar conhecer detalhes da implementação do software.
API
Desta forma, entendemos que as APIs permitem uma interoperabilidade entre aplicações. Em outras palavras, a comunicação entre aplicações e entre os usuários.
Node.js
Ambiente de execução Javascript server-side, que não depende de um browser, não é uma linguagem de programação.
Utilizada por grandes empresas no mercado de tecnologia, como Netflix, Uber e Linkedin.
Altamente escalável, com suporte na maioria de serviços em nuvem, como AWS, Google Cloud e Digital Ocean.
História
Criado em 2009, apesar do JavaScript possuir mias de 20 anos.
Favorecida pela rápida evolução da Web nos últimos anos.
Características
Assíncrona e single-thread.
Apenas uma thread é responsável por tratar as requisições, chamada de Event Loop.
Vantagens
Flexibilidade
Tem a maior plataforma de gerenciamento de pacotes, o NPM.
Leveza
Necessita de poucos recursos computacionais.
Combinação com ferramentas como Docker trazem ganhos significativos na velocidade de deploy.
Indicada para arquitetura de micro serviços e serverless.
Alta produtividade
Maior repositório do mundo.
Mesma linguagem do front-end, full-stack.
Deploys mais rápidos.
Desvantagens
JS pode incomodar pessoas que gostam de linguagens rígida.
JS é uma linguagem recente.
Assincronismo complica conforme a complexidade de requisições aumenta. Recursos como Async/Await (ES7) e Promisses (ES6) resolvem problemas de aninhamento de funções e diminuem a complexidade de depuração.
Pra que serve?
Aplicações
-
APIS;
-
Back-end de jogos e apps de mensagens;
-
Aplicações em tempo real com Socket.io;
Pacotes Node.js
NPM
O Node Package Manager consiste muito mais em um kit de ferramentas para desenvolvimento do que somente um instalador de pacotes.
Extremamente lento.
Yarn
Gerenciador de dependências mantido por um grupo de desenvolvedores do Babel JS, Facebook, Ember.js entre outros, criado para ser uma opção ao desenvolvedor.
Recomendado para projetos com muitas dependências.
Compatível com os registros NPM.
npm install -g yarn
yarn
Instalando o Yarn
cd project/folder
yarn init
Inicializando o projeto
Visual Code Studio
{
"name": "nodeapi",
"version": "1.0.0",
"main": "app.js",
"license": "MIT",
"scripts": {
"start": "node app.js"
},
"dependencies": {
},
"devDependencies": {
}
}
Entendendo o package.json
echo "console.log('Minha aplicação Node.js')" > app.js
Criando o arquivo app.js
Rodando a aplicação
yarn start
Express
Express
O Express.js é um dos frameworks mais utilizados do Node.js
É minimalista, rápido e possui inúmeras contribuições implementadas:
-
Flexível;
-
Utilitários HTTP para criação de apis;
-
Ótimo desempenho.
yarn add express
Adicionado o Express
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('Hello World!');
})
app.listen(port, () => {
console.log(`Aplicação rodando em http://localhost:${port}`);
})
Criando sua primeira rota
Roteamento
Determinação de como um aplicativo responde a uma solicitação do cliente por um endpoint específico, que é uma URI (ou caminho) e um método de solicitação HTTP específico (GET, POST, PUT ou DELETE).
var express = require('express');
var app = express();
app.METHOD(PATH, HANDLER)
Roteamento
var express = require('express');
var app = express();
app.get('/', function(req, res) {
res.send('Bem vindo!');
});
Roteamento
app.get('/', function(req, res) {
if (req.params.id) { // ... }
if (req.body.login) { // ... }
res.send('Bem vindo!');
});
Objetos req e res
Ao implementar uma rota, temos acesso a alguns objetos importantes nas requisições HTTP.
req: contém a requisição que está sendo enviada.
res: objeto pelo qual manipulamos a resposta dada a requisição.
Métodos de Respostas
express.Router
Classe para criar rotas modulares e montáveis.
const express = require('express');
const router = express.Router();
router.get('/', function(req, res) {
res.json([]);
});
module.exports = router;
module.exports
Responsável por tornar visível nossos códigos em outras partes da aplicação, para que futuramente possa ser carregado em outro local por meio de require.
const express = require('express');
const usuario = require('./routes/usuario');
const app = express();
app.use('/usuario', usuario);
body-parser
Pra tudo no Node.js temos um módulo. O body-parser faz a conversão do body da requisição para diversos formatos, como o JSON.
const express = require('express');
const bodyParser = require('body-parser');
const usuario = require('./routes/usuario');
const app = express();
app.use(bodyParser.json());
app.use('/usuario', usuario);
yarn add body-parser
body-parser
Assim, podemos acessar os dados que estão chegando por meio do body da requisição HTTP.
router.post('/', function(req, res) {
console.log(req.body);
res.json({});
});
nodemon
Pacote para Node.js que reinicia a aplicação caso sejam encontradas alterações em arquivos do projeto, ideal para ambientes de dev.
{
"name": "nodeapi",
...
"scripts": {
"start": "nodemon app.js"
}
}
yarn add nodemon
Insominia
Software para escrever requisições HTTP de maneira fácil e visual.
Desafio
Criar uma aplicação Node.js, no formato de API, aplicando os padrões REST que possua rotas de forma estruturada para os seguintes recursos:
-
Usuário;
-
Nota;
-
Checklist;
-
Tag.
ECMAScript
ECMAScript
Antes que o JavaScript se tornasse popular, para que a linguagem evoluísse obedecendo a determinados padrões e normativas, os criadores do JavaScript se associaram ao ECMA (European Computer Manufactures Association) em 1996.
ECMAScript
Como o nome JavaScript já havia sido patenteado pela Sun Microsystems (atual Oracle), optou-se por se definir um novo nome à linguagem utilizando a junção das palavras ECMA e JavaScript, surgindo então o ECMAScript.
ECMAScript
Como o nome JavaScript ficou popular na comunidade, a linguagem é chamada por este nome até hoje, sendo o ECMAScript referenciado apenas para se determinar a versão da linguagem.
const express = require('express');
const router = express.Router();
Desestruturação
const { Router } = require('express');
const router = Router();
ES5
ES6
const array = [1, 2, 3];
const firstElement = array[0];
console.log(firstElement); // 1
Desestruturação
const [elemento1, elemento2, elemento3] = [1, 2, 3];
console.log(elemento1, elemento2, elemento3); // 1, 2, 3
ES5
ES6
const body = {
nome: "Alan",
sobreNome: "Santos"
};
const nome = body.name;
const sobreNome = body.sobreNome;
console.log(nome, sobreNome); // Alan Santos
Desestruturação
const body = {
name: "Alan",
sobreNome: "Santos"
};
const { nome, sobreNome } = body;
console.log(nome, sobreNome); // Alan Santos
ES5
ES6
const getName = function (param1, param2) {
});
Arrow Functions
const getName = (param1, param2) => {
});
ES5
ES6
router.get('/', function(req, res) {
});
Arrow Functions
router.get('/', (req, res) => {
});
ES5
ES6
Promisses
É um objeto usado para processamento assíncrono. Um Promise (de "promessa") representa um valor que pode estar disponível agora, no futuro ou nunca.
Promisses
fetch(`http://swapi.co/api/people/${id}`)
.then(function(response) {
return response.json()
})
.then(function(person) {
console.log(person.name)
})
.catch(function(error) {
console.log(error)
});
ES5
Aninhamento
Async/Await
Com essa funcionalidade, é possível escrever código assíncrono como se estivéssemos escrevendo código síncrono.
try {
const response = await fetch(`http://swapi.co/api/people/${id}`);
const person = await response.json();
console.log(person.name);
} catch (error) {
console.log(error);
}
Async/Await
ES7
fetch(`http://swapi.co/api/people/${id}`)
.then(response => response.json())
.then(person => {
console.log(person);
console.log(person.name);
})
.catch(error => console.log(error));
ES6
const { Router } = require('express');
const router = Router();
router.get('/', async (req, res) => {
try {
const response = await fetch(`http://swapi.co/api/people/${id}`);
const person = await response.json();
console.log(person.name);
res.send(person);
} catch (error) {
console.log(error);
res.send(error);
}
});
Async/Await
ES7
const getPerson = async () => {
try {
const response = await fetch(`http://swapi.co/api/people/${id}`);
const person = await response.json();
console.log(person.name);
return person;
} catch (error) {
console.log(error);
}
});
Async/Await
ES7
Aplicando os recursos do ECMA
Aplicar em nosso projeto os conceitos que conhecemos na aula de hoje, como arrow functions e desestruturação.
Integrando ao
Banco de Dados
Capacidade de Conexão
Conectar à banco de dados em aplicativos do Express é apenas uma questão de se carregar um driver Node.js apropriado para o banco de dados no seu aplicativo.
npm install pg pg-hstore
// ou
yarn add pg pg-hstore
Instalação do Driver
ORM
(Object Relational Mapper) é uma técnica de mapeamento objeto relacional que permite fazer uma relação dos objetos com os dados que os mesmos representam.
Sequelize
Sequelize
Sequelize é um ORM baseado em promises para Postgres, MySQL, MariaDB, SQLite e Microsoft SQL Server.
Possui suporte sólido de transações, relações, replicação de leitura e muito mais.
npm install sequelize
// ou
yarn add sequelize
Instalação
const { Sequelize } = require('sequelize');
const database = {};
const options = {
username: 'postgres',
password: 'postgres',
database: 'notas',
host: 'localhost',
dialect: 'postgres',
};
const sequelize = new Sequelize(options);
sequelize
.authenticate()
.then(() => console.log(`Conectado com sucesso ao banco ${options.database}`))
.catch((err) => console.log(`Falha ao conectar ao banco ${options.database}: ${err}`));
database.sequelize = sequelize;
database.Sequelize = Sequelize;
module.exports = database;
Conexão
Desafio
Após instalar o postgres e configurá-lo em seu ambiente de desenvolvimento, realize a conexão da sua aplicação Node.js.
Tutorial de instalação do Postgres
Desafio
Após instalar o postgres e configurá-lo em seu ambiente de desenvolvimento, realize a conexão da sua aplicação Node.js.
Tutorial de instalação do Postgres
Criação de Modelos
Modelos
Modelos são a essência do Sequelize. São abstrações que representam as tabelas do banco de dados.
Os modelos dizem ao Sequelize informações importantes como nome da tabela e seus atributos.
Um modelo possui um nome, que não necessita ser o mesmo da tabela.
Modelo
module.exports = function(sequelize, DataTypes) {
const Usuario = sequelize.define(
'usuario',
{
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
nome: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false
},
senha: {
type: DataTypes.STRING,
allowNull: false
},
avatar: {
type: DataTypes.STRING,
allowNull: true
}
},
{
tableName: 'usuario',
timestamps: false
}
);
return Usuario;
};
Associações
As associações permitem acesso a objetos relacionados a outros em um banco de dados.
São 4 tipos de associações disponíveis no Sequelize:
HasOne;
BelongsTo;
HasMany;
BelongsToMany.
[
{
"id": 1,
"titulo": "Teste",
"descricao": null,
"usuarioId": 1,
"usuario": {
"id": 1,
"nome": "Alan",
"email": "alansantos@grupointegrado.br"
}
}
]
Dado Associado
[
{
"id": 1,
"nome": "Alan",
"email": "alansantos@grupointegrado.br",
"notas": [
{
"id": 1
},
{
"id": 2
}
]
}
]
Dado Associado
HasMany
module.exports = function(sequelize, DataTypes) {
const Usuario = sequelize.define(
'usuario',
{
// ...
},
{
tableName: 'usuario',
timestamps: false
}
);
Usuario.associate = function(models) {
this.hasMany(models.Nota, { foreignKey: 'usuarioId' });
}
return Usuario;
};
BelongsTo
module.exports = function(sequelize, DataTypes) {
const Nota = sequelize.define(
'nota',
{
// ...
},
{
tableName: 'nota',
timestamps: false
}
);
Nota.associate = function(models) {
this.belongsTo(models.Usuario, {
foreignKey: 'usuarioId'
});
}
return Nota;
};
Carregando os Modelos
const { Sequelize, DataTypes } = require('sequelize');
const _Usuario = require('./usuario');
const _Nota = require('./nota');
const database = {};
// ...
let Usuario = _Usuario(sequelize, DataTypes);
let Nota = _Nota(sequelize, DataTypes);
database['Usuario'] = Usuario;
database['Nota'] = Nota;
for (const key in database) {
if (database[key].associate) database[key].associate(database);
}
// ...
module.exports = database;
Operações Básicas
await Usuario.create({
nome: "Alan",
email: "alansantos@grupointegrado.br"
});
let user = await Usuario.findOrCreate({
defaults: {
nome: "Alan",
email: "alansantos@grupointegrado.br"
},
where: {
email: "alansantos@grupointegrado.br"
}
});
console.log(user.isNewRecord);
Create
await Usuario.update({
nome: "Alan",
email: "alansantos@grupointegrado.br"
}, {
where: {
id
}
});
Update
await Usuario.destroy({
where: {
id
}
});
Destroy
await Usuario.findAll();
await Usuario.findAll({
where: {
id
}
});
await Usuario.findAll({
attributes: ['id', 'nome', 'email', 'avatar'],
where: {
id
}
});
Consultas
await Nota.findAll({
where: {
id
},
include: [
{
model: Usuario
}
]
});
Consultas Associativas
const { Nota, Checklist, sequelize } = require('../models');
const transaction = await sequelize.transaction();
try {
await Nota.create(nota, {
transaction
});
await Checklist.create(checklist, {
transaction
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
}
Transações
Desafio
Para as rotas criadas em seu projeto, implementar controllers para:
-
POST
-
PUT;
-
DELETE;
-
Respostas para a rota GET. Essa rota pode receber um id ou não e realizar a busca do recurso ou recursos, de acordo com a especificação.
Fazer o commit e enviar para o repositório GitHub e publicar o link do repositório na entrega.
Programação Web Avançada
By Alan Ferreira dos Santos
Programação Web Avançada
- 540