Exercício – Criar um aplicativo Web básico

Concluído

Até agora, você tem o MongoDB e o Node.js instalados em sua VM do Ubuntu. Agora é hora de criar um aplicativo Web básico para ver as coisas em ação. Ao longo do caminho, você verá como o AngularJS e o Express se encaixam.

Uma ótima maneira de aprender é com exemplos. O aplicativo Web que você compilará implementa um banco de dados de catálogo básico. O aplicativo Web permite que você liste informações sobre livros, adicione novos livros e exclua livros existentes.

O aplicativo Web que você verá aqui demonstra muitos conceitos que se aplicam a aplicativos Web da pilha MEAN. Com base em suas necessidades e interesses, você pode explorar os recursos de que precisa para criar seus próprios aplicativos de pilha MEAN.

Veja como será o aplicativo Web dos Livros.

Screenshot of a web page with a form and submission button.

Veja como cada componente da pilha MEAN se ajusta.

  • O MongoDB armazena informações sobre livros.
  • O Express.js encaminha cada solicitação HTTP para o manipulador adequado.
  • O AngularJS conecta a interface do usuário à lógica de negócios do programa.
  • O Node.js hospeda o aplicativo do lado do servidor.

Importante

Para fins de aprendizado, aqui você está criando um aplicativo Web básico. Sua finalidade é testar sua pilha MEAN e dar uma ideia de como ela funciona. O aplicativo não é suficientemente seguro nem está pronto para uso para produção.

E quanto ao Express?

Até agora, você instalou o MongoDB e o Node.js em sua VM. E quanto ao Express.js, o E do acrônimo MEAN?

O Express.js é uma estrutura de servidor Web criada para Node.js que simplifica o processo de criação de aplicativos Web.

O principal objetivo do Express é lidar com o roteamento de solicitações. Roteamento se refere a como o aplicativo responde a uma solicitação para um ponto de extremidade específico. Um ponto de extremidade é composto por um caminho, ou URI, e por um método de solicitação, como GET ou POST. Por exemplo, você pode responder a uma solicitação GET para o ponto de extremidade /book fornecendo a lista de todos os livros no banco de dados. Você pode responder a uma solicitação POST para o mesmo ponto de extremidade adicionando uma entrada ao banco de dados com base em campos que o usuário inseriu em um formulário da Web.

No aplicativo Web que você criará em breve, você usará o Express para rotear solicitações HTTP e retornar o conteúdo da Web para seu usuário. O Express também pode ajudar seus aplicativos Web a funcionarem com cookies HTTP e processarem cadeias de caracteres de consulta.

O Express é um pacote de Node.js. Você usa o utilitário npm, que vem com o Node.js, para instalar e gerenciar pacotes do Node.js. Mais adiante nesta unidade, você criará um arquivo chamado package.json para definir o Express e outras dependências e, em seguida, executará o comando npm install para instalar essas dependências.

E quanto ao AngularJS?

Assim como o Express, você ainda não instalou o AngularJS, o A do acrônimo MEAN.

O AngularJS facilita a escrita e o teste de aplicativos Web porque permite que você separe melhor a aparência da página da Web, o código HTML, do comportamento dela. Se você estiver familiarizado com o padrão MVC (Model-View-Controller) ou com o conceito de associação de dados, o AngularJS será familiar para você.

O AngularJS é o que chamamos de estrutura JavaScript de front-end, o que significa que ele precisa estar disponível apenas no cliente que acessa o aplicativo. Em outras palavras, o AngularJS é executado no navegador da Web do usuário, não em seu servidor Web. E, como AngularJS é JavaScript, você pode usá-lo para buscar com facilidade dados de seu servidor Web para mostrar na página.

Na verdade, você não instala o AngularJS. Em vez disso, você adiciona uma referência ao arquivo JavaScript na página HTML, assim como faria com outras bibliotecas JavaScript. Há várias maneiras de incluir o AngularJS em suas páginas da Web. Aqui, você carregará o AngularJS de uma rede de distribuição de conteúdo ou CDN. Uma CDN é uma maneira de distribuir imagens, vídeos e outros conteúdos geograficamente para melhorar as velocidades de download.

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

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

Observação

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 é muito usado para compilar aplicativos Web. Enquanto o AngularJS é baseado em JavaScript, o Angular é baseado em TypeScript, uma linguagem de programação que torna mais fácil escrever programas JavaScript.

Como compilar o aplicativo?

Aqui, você usará um processo básico. Você escreverá o código de aplicativo do Cloud Shell e, em seguida, usará o SCP ou protocolo de cópia seguro para copiar os arquivos para sua VM. Em seguida, você iniciará o aplicativo Node.js e verá os resultados no navegador.

Na prática, normalmente você escreveria e testaria o aplicativo Web em um ambiente mais local, como no laptop ou em uma máquina virtual executada localmente. Você poderia, então, armazenar seu código em um sistema de controle de versão, como o Git, e usar um sistema de integração contínua e entrega contínua ou CI/CD como o Azure DevOps para testar suas alterações e fazer upload delas na VM. Indicaremos mais recursos no final deste módulo.

Criar o aplicativo Web Books

Aqui, você criará todo o código, o script e os arquivos HTML que compõem seu aplicativo Web. Para fins de brevidade, destacaremos as partes importantes de cada arquivo, mas não entraremos nos detalhes completos.

Se você ainda estiver conectado à VM via SSH, execute exit para sair da sessão de SSH e voltar para o Cloud Shell.

exit

Agora, você está de volta à sua sessão do Cloud Shell.

Criar os arquivos

  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
    

    Veja o que está incluído:

    • Books é o diretório raiz do projeto.
      • server.js define o ponto de entrada para o aplicativo Web. Ele carrega os pacotes necessários do Node.js, especifica a porta para escutar e começa a escutar o tráfego HTTP de entrada.
      • package.json fornece informações sobre seu aplicativo, incluindo o nome, a descrição e quais pacotes do Node.js seu aplicativo precisa executar.
    • – contém o código que é executado no servidor.
      • model.js define a conexão de banco de dados e o esquema. Pense nele como o modelo de dados de seu aplicativo.
      • routes.js lida com o roteamento de solicitações. Por exemplo, ele define solicitações GET para o ponto de extremidade /book fornecendo a lista de todos os livros no banco de dados.
    • – contém arquivos que são fornecidos diretamente para o navegador do cliente.
      • index.html contém a página de índice. Ele contém um formulário da Web que permite ao usuário enviar informações sobre livros. Ele também exibe todos os livros no banco de dados e permite que você exclua as entradas do banco de dados.
      • script.js contém o código JavaScript que é executado no navegador do usuário. Ele pode enviar solicitações ao servidor para listar livros, adicionar livros ao banco de dados e excluir livros do banco de dados.
  2. Execute o comando code para abrir os arquivos por meio do editor do Cloud Shell.

    code Books
    

Criar o modelo de dados

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

    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 você colar ou alterar o código em um arquivo no editor, salve usando o menu "..." ou a tecla de atalho (Ctrl + S no Windows e no Linux, Command + S no macOS).

    Esse código usa Mongoose para simplificar o processo de transferência de dados para dentro e fora do MongoDB. O Mongoose é um sistema baseado em esquema para modelagem de dados. O código define um documento de banco 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
    • Seu ISBN – ou International Standard Book Number –, que identifica exclusivamente o livro
    • O autor
    • O número de páginas que ele contém

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

Crie as rotas do Express.js que manipulam as 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;
    

    Esse código cria quatro rotas para o aplicativo. Veja uma breve visão geral de cada uma delas.

    Verbo HTTP Ponto de extremidade Descrição
    GET /book Recupera todos os livros do banco de dados.
    POST /book Cria um objeto Book com base nos campos que o usuário forneceu no formulário da Web e grava o objeto no banco de dados.
    DELETE /book/:isbn Exclui o livro conforme identificado pelo ISBN do banco de dados.
    GET * Retorna a página de índice quando nenhuma outra rota é correspondente.

    O Express.js pode fornecer respostas HTTP diretamente no código de manipulação de rota ou fornecer conteúdo estático de arquivos. Este código mostra ambos. As três primeiras rotas retornam dados JSON para solicitações de API de livro. A quarta rota (caso padrão) retorna o conteúdo do arquivo de índice, index.html.

Crie o aplicativo 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 entraremos em muitos detalhes sobre como o módulo e os controladores funcionam aqui, mas você usará esses nomes na próxima etapa para associar a interface do usuário (código HTML) com a lógica de negócios do aplicativo.

    Anteriormente, você criou quatro rotas que manipulam várias operações GET, POST e DELETE no servidor. Esse código se parece com as mesmas operações, mas do lado do cliente (navegador da Web do usuário).

    A função getData, por exemplo, envia uma solicitação GET para o ponto de extremidade /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. Observe como os dados JSON resultantes são atribuídos à variável $scope.books. Você aprenderá como isso 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. Você pode examinar as funções del_book e add_book para ter uma noção de como elas funcionam. Não é necessário que o código do lado do cliente corresponda ao manipulador padrão do servidor, pois o manipulador padrão retorna a página de índice e não os dados JSON.

Criar a interface do usuário

  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>
    

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

    Embora esse seja um código HTML padrão, os atributos HTML ng- podem não ser familiares para você. Esses atributos HTML conectam o código do AngularJS à interface do usuário. Por exemplo, ao clicar em Adicionar, o AngularJS executará a chamada da função add_book, que enviará os dados do formulário ao servidor.

    Você pode examinar o código aqui para ter uma ideia de como cada um dos atributos ng- se relaciona com a 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'));
    });
    

    O próprio código cria o aplicativo Web. Ele fornece arquivos estáticos do diretório public e usa as rotas definidas anteriormente para manipular as solicitações.

Definir informações e dependências do pacote

Lembre-se de que package.json fornece informações sobre seu aplicativo, incluindo o nome, a descrição e quais pacotes do Node.js seu aplicativo precisa 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"
      }
    }
    

Você verá informações ou metadados sobre seu aplicativo, incluindo o nome, a descrição e a licença.

O campo repository especifica onde o código é mantido. Para referência, posteriormente você pode examinar o código no GitHub na URL mostrada aqui.

O campo main define o ponto de entrada do aplicativo. Ele é fornecido aqui para fins de integridade, mas não é importante porque você não está planejando publicar o aplicativo como um pacote do Node.js para outras pessoas baixarem e usarem.

O campo dependencies é importante. Ele define os pacotes de Node.js de que seu aplicativo precisa. Em breve, você se conectará à sua VM uma segunda vez e executará o comando npm install para instalar esses pacotes.

Normalmente, pacotes do Node usam o esquema de controle de versão semântico. O número de versão tem três componentes: versão principal, versão secundária e patch. A notação de til ~ aqui instrui o npm a instalar a versão mais recente do patch sob as versões principais e secundárias fornecidas. As versões vistas aqui são as mais recentes com as quais este módulo foi testado. Na prática, você pode incrementar a versão ao longo do tempo conforme atualiza e testa seu aplicativo para usar as funcionalidades mais recentes que cada pacote dependente fornece.

Copie os arquivos para sua VM

Antes de prosseguir, verifique se você tem o endereço IP da VM à mão. Se 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. Você terminou de editar os arquivos. Verifique se você salvou as alterações em cada arquivo e, em seguida, feche o editor.

    Para fechar o editor, selecione as reticências no canto superior direito da tela e selecione Fechar Editor.

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

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

Instalar pacotes adicionais do Node

Digamos que, durante o processo de desenvolvimento, você identificou pacotes adicionais do Node que deseja usar. Por exemplo, lembre-se de que app/model.js inicia com esta linha.

var mongoose = require('mongoose');

Lembre-se de que o aplicativo usa Mongoose para ajudar a transferir dados para dentro e fora do seu banco de dados do MongoDB.

O aplicativo também exige o Express.js e os pacotes body-parser. O body-parser é um plug-in que habilita o Express a trabalhar com os dados no formulário da Web enviado pelo cliente.

Vamos conectar sua VM e instalar os pacotes especificados em package.json.

  1. Antes de se conectar à sua VM, verifique se você 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. Assim como fez anteriormente, crie uma conexão SSH para a VM:

    ssh azureuser@$ipaddress
    
  3. Passe para o diretório Books no diretório inicial:

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

    sudo apt install npm -y && npm install
    

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

Testar o aplicativo

Agora, você está pronto para testar seu aplicativo Web Node.js!

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

    sudo nodejs server.js
    

    Esse comando inicia o aplicativo escutando na porta 80 por solicitações HTTP de entrada.

  2. Em uma guia separada do navegador, navegue até o endereço IP público da sua VM.

    É possível ver a página de índice que inclui um formulário da Web.

    Screenshot of the book web page with a form and submission button.

    Tente adicionar alguns livros ao banco de dados. A página atualiza a lista completa de livros cada vez que você adiciona um livro.

    Screenshot of the book web page with sample data populated.

    Para excluir um livro do banco de dados, também será possível clicar em Excluir.