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

Concluído

Até agora, tem o MongoDB e o Node.js instalados na VM do Ubuntu. Agora é altura de criar uma aplicação Web básica para ver tudo em ação. Ao longo do processo, pode ver como o AngularJS e o Express se adaptam.

Uma ótima maneira de aprender é com um exemplo. A aplicação Web que vai criar implementa uma base de dados de livros básica. O aplicativo Web permite listar informações sobre livros, adicionar novos livros e excluir livros existentes.

A aplicação Web que vai ver aqui demonstra muitos conceitos que se aplicam à maioria das aplicações Web da 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.

Veja a seguir a aparência da aplicação Web Livros.

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

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, instalou o MongoDB e o Node.js na VM. E quanto ao Express.js, o E na sigla MEAN?

Express.js é uma estrutura de servidor Web criada para o 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. Pode responder a um pedido POST para o mesmo ponto final ao adicionar uma entrada à base de dados com base nos campos que o utilizador inseriu num formulário Web.

Na aplicação Web que vai criar em breve, vai utilizar o Express para encaminhar os pedidos HTTP e retornar o conteúdo da Web para o utilizador. 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ê criará um arquivo nomeado package.json para definir o Express e outras dependências e, em seguida, executará o npm install comando para instalar essas dependências.

E quanto ao AngularJS?

Tal como o Express, ainda não instalou o AngularJS, o A no acrónimo MEAN.

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 estiver familiarizado com o padrão do model-view-controller (MVC) ou o conceito de enlace de dados, o AngularJS ser-lhe-á familiar.

O AngularJS é aquilo que chamamos uma arquitetura JavaScript de front-end, o que significa que precisa apenas de estar disponível no cliente que acede à aplicação. 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ê carregará o AngularJS de uma rede de distribuição de conteúdo ou 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 ainda este código, contudo, aqui está um exemplo que carrega o AngularJS a partir 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 vou criar a aplicação?

Aqui, irá utilizar um processo básico. Irá escrever código da aplicação a partir do Cloud Shell e, em seguida, utilizar o SCP, ou protocolo de cópia de segurança, para copiar os ficheiros para a VM. Em seguida, você iniciará o aplicativo Node.js e verá os resultados em 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. Em seguida, você pode 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 carregá-las em sua VM. Vamos indicar-lhe mais recursos no final deste módulo.

Criar a aplicação Web Livros

Aqui, você criará todos os arquivos de código, script e HTML que compõem seu aplicativo Web. Por uma questão de brevidade, podemos destacar as partes importantes de cada ficheiro, não vamos abordar as partes em detalhe.

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
    

    Inclui o seguinte:

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

    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
    • Seu International Standard Book Number (ISBN), que identifica exclusivamente o livro
    • O autor
    • O número de páginas que contém

    Em seguida, vai criar processadores de HTTP que mapeiam pedidos GET, POST e DELETE para as operações de base 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 com o nome "myApp" e um controlador com o nome "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. Recorde-se que o servidor processa este pedido ao recuperar informações sobre todos os livros da base de dados e devolve 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. 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 seja o código HTML padrão, os atributos HTML ng- podem não lhe ser familiares. 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.

Crie 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. Ele é fornecido aqui para integridade, mas não é importante porque você não está planejando publicar seu aplicativo como um pacote 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, vai ligar-se à VM uma segunda vez e executar o comando npm install para instalar estes 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 pacotes de Nós adicionais

Digamos que, durante o processo de desenvolvimento, identificou pacotes adicionais de Nós que pretende utilizar. 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.

O aplicativo também requer Express.js e os pacotes de 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. Como você fez anteriormente, crie uma conexão SSH para sua VM:

    ssh azureuser@$ipaddress
    
  3. Mover para o diretório sob o Books 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.

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

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

    Screenshot of the book web page with sample data populated.

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