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.

Desafio

 

Essa atividade deverá ser realizada individualmente, seguindo os  passos abaixo:

  1. Criar um repositório no GitHub;

  2. Convidar o usuário woodyalan como participante do projeto;

  3. Publicar a URL do repositório com os códigos atualizados.

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

Tabelas

 

O próximo passo é criar nossas tabelas, usando o script dos objetos do banco

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.