Exercício – criar uma aplicação Web básica

Concluído

Até agora, você tem MongoDB e Node.js instalado em sua máquina virtual Ubuntu (VM). Agora é altura de criar uma aplicação Web básica para ver tudo em ação. Ao longo do caminho, você vê como o AngularJS e o Express se encaixam.

Uma ótima maneira de aprender é com um exemplo. O aplicativo Web que você cria implementa um banco de dados básico de livros. O aplicativo Web permite listar informações sobre livros, adicionar novos livros e excluir livros existentes.

O aplicativo Web que você vê aqui demonstra muitos conceitos que se aplicam à maioria dos aplicativos Web de pilha MEAN. Com base nas suas necessidades e nos seus interesses, pode explorar as funcionalidades de que precisa para compilar as suas próprias aplicações de pilha MEAN.

Eis o aspeto da aplicação Web Livros.

Captura de ecrã a mostrar uma página Web com um formulário e um botão de submissão.

Veja a seguir como cada componente da pilha MEAN encaixa.

  • O MongoDB armazena informações sobre os livros.
  • Express.js roteia cada solicitação HTTP para o manipulador apropriado.
  • O AngularJS liga a interface de utilizador à lógica de negócio do programa.
  • O Node.js aloja a aplicação do lado do servidor.

Importante

Para efeitos de aprendizagem, está a criar uma aplicação Web básica. A finalidade é testar a sua pilha MEAN e dar-lhe uma noção de como funciona. O aplicativo não é suficientemente seguro ou está pronto para uso em produção.

E quanto ao Express?

Até agora, você instalou o MongoDB e Node.js em sua VM. E quanto a Express.js, o E na sigla MEAN?

Express.js é uma estrutura de servidor web construída para Node.js que simplifica o processo de criação de aplicações web.

A principal finalidade do Express é processar o encaminhamento de pedidos. Encaminhamento refere-se à forma como a aplicação responde a um pedido para um ponto final específico. Um ponto de extremidade é composto por um caminho, ou URI, e um método de solicitação, como GET ou POST. Por exemplo, pode responder a um pedido GET para o ponto final /book ao fornecer a lista de todos os livros na base de dados. Você pode responder a uma solicitação POST para o /book ponto de extremidade adicionando uma entrada ao banco de dados com base nos campos que o usuário inseriu em um formulário da Web.

No aplicativo Web que você cria em breve, você usa o Express para rotear solicitações HTTP e retornar conteúdo da Web para seu usuário. O Express também pode ajudar as suas aplicações Web a trabalhar com cookies HTTP e a processar cadeias de consulta.

O Express é um pacote Node.js. Utilize o utilitário npm, fornecido com o Node.js, para instalar e gerir pacotes Node.js. Mais adiante nesta unidade, você cria um arquivo chamado package.json para definir Express e outras dependências e, em seguida, executa o npm install comando para instalar essas dependências.

E quanto ao AngularJS?

Assim como o Express, o AngularJS, o A na sigla MEAN, ainda não está instalado.

O AngularJS torna as aplicações Web mais fáceis de escrever e testar porque lhe permite separar melhor a aparência da sua página Web — o seu código HTML — da forma como a sua página Web se comporta. Se você estiver familiarizado com o padrão model–view–controller (MVC) ou com o conceito de vinculação de dados, o AngularJS deve estar familiarizado com você.

AngularJS é uma estrutura JavaScript front-end , o que significa que ele só precisa estar disponível no cliente que acessa o aplicativo. Por outras palavras, o AngularJS é executado no browser do utilizador, não no seu servidor Web. E, como o AngularJS é JavaScript, pode utilizá-lo para obter facilmente dados do seu servidor Web para mostrar na página.

Não precisa realmente de instalar o AngularJS. Em vez disso, pode adicionar uma referência ao ficheiro JavaScript na sua página HTML, tal como o que faz com outras bibliotecas JavaScript. Existem várias formas de incluir o AngularJS nas páginas Web. Aqui, você carrega o AngularJS de uma rede de distribuição de conteúdo (CDN). Uma CDN é uma forma de distribuir imagens, vídeos e outros conteúdos geograficamente para melhorar as velocidades de transferência.

Não adicione este código ainda, mas aqui está um exemplo que carrega AngularJS de uma CDN. Normalmente, você adiciona esse código à <head> seção da sua página HTML.

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script>

Nota

Não confunda o AngularJS com o Angular. Embora muitos dos conceitos sejam semelhantes entre os dois, o AngularJS é o predecessor do Angular. O AngularJS ainda é bastante utilizado para criar aplicações Web. Enquanto o AngularJS é baseado no JavaScript, o Angular é baseado em TypeScript, uma linguagem de programação que torna mais fácil escrever programas de JavaScript.

Como faço para criar o aplicativo?

Aqui, você usa um processo básico. Você escreve o código do aplicativo a partir do Cloud Shell e, em seguida, usa o protocolo de cópia segura (SCP) para copiar os arquivos para sua VM. Em seguida, inicie o aplicativo Node.js e veja os resultados no seu navegador.

Na prática, você normalmente escreve e testa seu aplicativo Web em um ambiente mais local, como de seu laptop ou de uma máquina virtual executada localmente. Você pode armazenar seu código em um sistema de controle de versão, como o Git. Em seguida, use um sistema de integração contínua e entrega contínua (CI/CD), como o Azure DevOps, para testar suas alterações e carregá-las em sua VM. Indicamos mais recursos no final deste módulo.

Criar a aplicação Web Livros

Aqui, você cria todos os arquivos de código, script e HTML que compõem seu aplicativo Web. Para maior brevidade, destacamos as partes importantes de cada arquivo, mas não entramos em detalhes completos.

Se ainda estiver ligado à VM através de SSH, execute exit para sair da sessão SSH e regressar ao Cloud Shell.

exit

Regressou à sua sessão do Cloud Shell.

Criar os ficheiros

  1. No Cloud Shell, execute estes comandos para criar as pastas e arquivos para seu aplicativo Web:

    cd ~
    mkdir Books
    touch Books/server.js
    touch Books/package.json
    mkdir Books/app
    touch Books/app/model.js
    touch Books/app/routes.js
    mkdir Books/public
    touch Books/public/script.js
    touch Books/public/index.html
    

    O aplicativo Web inclui as seguintes pastas e arquivos:

    • Books é o diretório raiz do projeto.
      • server.js define o ponto de entrada para a aplicação Web. Este carrega os pacotes Node.js necessários, especifica a porta a escutar e começa a escutar o tráfego HTTP de entrada.
      • package.json fornece informações sobre a aplicação, incluindo o nome, a descrição e os pacotes Node.js que a aplicação precisa de executar.
    • Books/app contém código que é executado no servidor.
      • model.js define a ligação da base de dados e o esquema. Pense nele como o modelo de dados da aplicação.
      • routes.js processa o encaminhamento de pedidos. Por exemplo, define pedidos GET para o ponto final /book ao fornecer a lista de todos os livros na base de dados.
    • Books/public contém ficheiros que são fornecidos diretamente ao browser do cliente.
      • index.html contém a página de índice. Contém um formulário Web que permite ao utilizador enviar informações sobre os livros. Também apresenta todos os livros no banco de dados e permite-lhe eliminar entradas na base de dados.
      • script.js contém o código JavaScript que é executado no browser do utilizador. Pode enviar pedidos para o servidor para listar livros, adicionar livros à base de dados e eliminar livros da base de dados.
  2. Execute o comando code para abrir os ficheiros através do editor do Cloud Shell.

    code Books
    

Criar o modelo de dados

  1. No editor, abra app/model.js e adicione o seguinte código:

    var mongoose = require('mongoose');
    var dbHost = 'mongodb://localhost:27017/Books';
    mongoose.connect(dbHost, { useNewUrlParser: true } );
    mongoose.connection;
    mongoose.set('debug', true);
    var bookSchema = mongoose.Schema( {
        name: String,
        isbn: {type: String, index: true},
        author: String,
        pages: Number
    });
    var Book = mongoose.model('Book', bookSchema);
    module.exports = Book;
    

    Importante

    Sempre que colar ou alterar código num ficheiro no editor, confirme que guarda posteriormente através do menu "..." ou da tecla de atalho (Ctrl+S no Windows e Linux, Comando+S no macOS).

    Este código utiliza o Mongoose para simplificar o processo de transferência de dados para dentro e para fora do MongoDB. O Mongoose é um sistema baseado em esquemas para a modelação de dados. O código define um documento de base de dados chamado "Livro" com o esquema fornecido. O esquema define quatro campos que descrevem um único livro:

    • O nome ou título do livro
    • O seu International Standard Book Number (ISBN) que identifica exclusivamente o livro
    • O autor
    • O número de páginas que contém

    Em seguida, você cria manipuladores HTTP que mapeiam solicitações GET, POST e DELETE para operações de banco de dados.

Criar as rotas Express.js que lidam com solicitações HTTP

  1. No editor, abra app/routes.js e adicione o seguinte código:

    var path = require('path');
    var Book = require('./model');
    var routes = function(app) {
        app.get('/book', function(req, res) {
            Book.find({}, function(err, result) {
                if ( err ) throw err;
                res.json(result);
            });
        });
        app.post('/book', function(req, res) {
            var book = new Book( {
                name:req.body.name,
                isbn:req.body.isbn,
                author:req.body.author,
                pages:req.body.pages
            });
            book.save(function(err, result) {
                if ( err ) throw err;
                res.json( {
                    message:"Successfully added book",
                    book:result
                });
            });
        });
        app.delete("/book/:isbn", function(req, res) {
            Book.findOneAndRemove(req.query, function(err, result) {
                if ( err ) throw err;
                res.json( {
                    message: "Successfully deleted the book",
                    book: result
                });
            });
        });
        app.get('*', function(req, res) {
            res.sendFile(path.join(__dirname + '/public', 'index.html'));
        });
    };
    module.exports = routes;
    

    Este código cria quatro rotas para a aplicação. Veja a seguir uma breve descrição geral de cada uma.

    Verbo HTTP Ponto final Description
    GET /book Obtém todos os livros da base de dados.
    POST /book Cria um objeto Book baseado nos campos que o utilizador forneceu no formulário Web e escreve esse objeto na base de dados.
    DELETE /book/:isbn Elimina o livro, conforme identificado pelo ISBN da base de dados.
    GET * Devolve a página de índice quando nenhuma outra rota é correspondida.

    Express.js pode servir respostas HTTP diretamente no código de manipulação de rotas ou pode servir conteúdo estático de arquivos. Este código mostra ambos. As três primeiras rotas devolvem dados JSON para pedidos da API do livro. A quarta rota (o caso padrão) devolve os conteúdos do ficheiro de índice, index.html.

Criar a aplicação JavaScript do lado do cliente

  1. No editor, abra public/script.js e adicione este código:

    var app = angular.module('myApp', []);
    app.controller('myCtrl', function($scope, $http) {
        var getData = function() {
            return $http( {
                method: 'GET',
                url: '/book'
            }).then(function successCallback(response) {
                $scope.books = response.data;
            }, function errorCallback(response) {
                console.log('Error: ' + response);
            });
        };
        getData();
        $scope.del_book = function(book) {
            $http( {
                method: 'DELETE',
                url: '/book/:isbn',
                params: {'isbn': book.isbn}
            }).then(function successCallback(response) {
                console.log(response);
                return getData();
            }, function errorCallback(response) {
                console.log('Error: ' + response);
            });
        };
        $scope.add_book = function() {
            var body = '{ "name": "' + $scope.Name +
            '", "isbn": "' + $scope.Isbn +
            '", "author": "' + $scope.Author +
            '", "pages": "' + $scope.Pages + '" }';
            $http({
                method: 'POST',
                url: '/book',
                data: body
            }).then(function successCallback(response) {
                console.log(response);
                return getData();
            }, function errorCallback(response) {
                console.log('Error: ' + response);
            });
        };
    });
    

    Observe como esse código define um módulo chamado myApp e um controlador chamado myCtrl. Não vamos analisar em detalhe a forma como o módulo e os controladores funcionam, mas vai utilizar estes nomes no próximo passo para vincular a interface do utilizador (código HTML) com a lógica de negócio da aplicação.

    Anteriormente, criou quatro rotas que processam várias operações GET, POST e DELETE no servidor. Este código é semelhante a essas mesmas operações, mas do lado do cliente (browser do utilizador).

    A função getData, por exemplo, envia um pedido GET para o ponto final /book. Lembre-se de que o servidor lida com essa solicitação recuperando informações sobre todos os livros do banco de dados e retornando essas informações como dados JSON na resposta. Observe como os dados JSON na resposta são atribuídos à $scope.books variável. Você aprenderá como esse código afeta o que o usuário vê na página da Web na próxima etapa.

    Esse código chama a função getData quando a página é carregada. Pode examinar as funções del_book e add_book para ter uma ideia de como funcionam. Você não precisa de código do lado do cliente para corresponder ao manipulador padrão do servidor, porque o manipulador padrão retorna a página de índice e não os dados JSON.

Criar a interface de utilizador

  1. No editor, abra public/index.html e adicione este código:

    <!doctype html>
    <html ng-app="myApp" ng-controller="myCtrl">
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script>
        <script src="script.js"></script>
    </head>
    <body>
        <div>
        <table>
            <tr>
            <td>Name:</td>
            <td><input type="text" ng-model="Name"></td>
            </tr>
            <tr>
            <td>Isbn:</td>
            <td><input type="text" ng-model="Isbn"></td>
            </tr>
            <tr>
            <td>Author:</td>
            <td><input type="text" ng-model="Author"></td>
            </tr>
            <tr>
            <td>Pages:</td>
            <td><input type="number" ng-model="Pages"></td>
            </tr>
        </table>
        <button ng-click="add_book()">Add</button>
        </div>
        <hr>
        <div>
        <table>
            <tr>
            <th>Name</th>
            <th>Isbn</th>
            <th>Author</th>
            <th>Pages</th>
            </tr>
            <tr ng-repeat="book in books">
            <td><input type="button" value="Delete" data-ng-click="del_book(book)"></td>
            <td>{{book.name}}</td>
            <td>{{book.isbn}}</td>
            <td>{{book.author}}</td>
            <td>{{book.pages}}</td>
            </tr>
        </table>
        </div>
    </body>
    </html>
    

    Este código cria um formulário HTML básico, com quatro campos para enviar dados do livro e uma tabela que exibe todos os livros armazenados no banco de dados.

    Embora esse código HTML seja padrão, os ng- atributos HTML podem não ser familiares para você. Os atributos HTML ligam o código do AngularJS à interface de utilizador. Por exemplo, quando seleciona Adicionar, o AngularJS chama a função add_book, que envia os dados do formulário para o servidor.

    Você pode examinar o código aqui para ter uma noção de como cada um dos atributos se relaciona com a ng- lógica de negócios do aplicativo.

Criar o servidor Express.js para hospedar o aplicativo

  1. No editor, abra server.js e adicione este código:

    var express = require('express');
    var bodyParser = require('body-parser');
    var app = express();
    app.use(express.static(__dirname + '/public'));
    app.use(bodyParser.json());
    require('./app/routes')(app);
    app.set('port', 80);
    app.listen(app.get('port'), function() {
        console.log('Server up: http://localhost:' + app.get('port'));
    });
    

    Este código cria a própria aplicação Web. Ele serve arquivos estáticos do public diretório e usa as rotas definidas anteriormente para lidar com solicitações.

Definir as informações e as dependências dos pacotes

Recorde-se que package.json fornece informações sobre a aplicação, incluindo o nome, a descrição e os pacotes Node.js que a aplicação precisa de executar.

  1. No editor, abra package.json e adicione este código:

    {
      "name": "books",
      "description": "Sample web app that manages book information.",
      "license": "MIT",
      "repository": {
        "type": "git",
        "url": "https://github.com/MicrosoftDocs/mslearn-build-a-web-app-with-mean-on-a-linux-vm"
      },
      "main": "server.js",
      "dependencies": {
        "express": "~4.16",
        "mongoose": "~5.3",
        "body-parser": "~1.18"
      }
    }
    

Pode ver informações, ou metadados, sobre a aplicação, incluindo o nome, a descrição e a licença.

O campo repository especifica onde é que o código é mantido. Para referência, pode consultar posteriormente o código no GitHub no URL apresentado aqui.

O campo main define o ponto de entrada da aplicação. Nós fornecemos aqui para completude. No entanto, o ponto de entrada só é importante se você estiver planejando publicar seu aplicativo como um pacote de Node.js para outras pessoas baixarem e usarem.

O campo dependencies é importante, pois define os pacotes Node.js que a aplicação precisa. Em breve, você se conecta à sua VM uma segunda vez e executa o npm install comando para instalar esses pacotes.

Normalmente, os pacotes de nós utilizam o esquema de versões Controlo de Versão Semântica. O número da versão contém três componentes: versão principal, versão secundária e patch. A notação til ~ aqui indica ao npm para instalar a versão mais recente do patch nas versões principais e secundárias fornecidas. As versões que você vê aqui são as mais recentes com as quais este módulo foi testado. Na prática, pode incrementar a versão ao longo do tempo à medida que atualiza e testa a sua aplicação para utilizar as funcionalidades mais recentes que cada pacote dependente fornece.

Copiar os ficheiros para a VM

Antes de continuar, certifique-se de que tem o endereço IP da sua VM à mão. Se você não o tiver, execute estes comandos do Cloud Shell para recuperá-lo:

ipaddress=$(az vm show \
  --name MeanStack \
  --resource-group "<rgn>[sandbox resource group name]</rgn>" \
  --show-details \
  --query [publicIps] \
  --output tsv)
echo $ipaddress
  1. Concluímos a edição dos ficheiros. Certifique-se de que guardou as alterações em cada ficheiro e, em seguida, feche o editor.

    Para fechar o editor, selecione as reticências no canto superior direito e, em seguida, selecione Fechar editor.

  2. Execute o seguinte scp comando para copiar o ~/Books conteúdo do diretório em sua sessão do Cloud Shell para o mesmo nome de diretório em sua VM:

    scp -r ~/Books azureuser@$ipaddress:~/Books
    

Instalar mais pacotes Node

Digamos que, durante o processo de desenvolvimento, você identificou mais pacotes de nó que deseja usar. Por exemplo, recorde-se que app/model.js começa com esta linha.

var mongoose = require('mongoose');

Recorde-se que a aplicação utiliza o Mongoose para ajudar a transferir dados para dentro e para fora da base de dados do MongoDB.

A aplicação também requer Express.js e os pacotes do analisador de corpo. Body-parser é um plugin que permite ao Express trabalhar com dados do formulário web enviado pelo cliente.

Vamos estabelecer ligação à VM e instalar os pacotes que especificou em package.json.

  1. Antes de ligar à VM, confirme que tem o endereço IP da VM à mão. Se você não o tiver, execute os comandos do Cloud Shell na seção anterior para recuperá-lo.

  2. Crie uma conexão SSH com sua VM, como fez anteriormente:

    ssh azureuser@$ipaddress
    
  3. Mover para o Books diretório sob o diretório base:

    cd ~/Books
    
  4. Execute npm install para instalar os pacotes dependentes:

    sudo apt install npm -y && npm install
    

Mantenha sua conexão SSH aberta para a próxima seção.

Testar a aplicação

Agora, está pronto para testar a aplicação Web do Node.js!

  1. ~/Books No diretório, execute este comando para iniciar o aplicativo Web:

    sudo nodejs server.js
    

    Este comando inicia a aplicação através da escuta na porta 80 por pedidos HTTP de entrada.

  2. Num separador do browser separado, navegue até ao endereço IP público da VM.

    Pode ver a página de índice, que inclui um formulário Web.

    Captura de ecrã a mostrar a página Web do livro com um formulário e um botão de submissão.

    Tente adicionar alguns livros à base de dados. Sempre que adicionar um livro, a página atualiza a lista completa de livros.

    Captura de ecrã a mostrar a página Web do livro com dados de exemplo preenchidos.

    Para eliminar um livro da base de dados, também pode selecionar Eliminar.