Construindo Back-End — parte 2

Lia Kassardjian
Zero e Umas
Published in
8 min readJul 28, 2020
Photo by Clément H on Unsplash

Na parte 1 dessa série, construímos uma aplicação de Back-End usando NestJS, um framework muito útil para construir aplicações em TypeScript para o lado do servidor. Porém, ao final da primeira parte, encontramos um problema: nossa aplicação era executada apenas localmente, na nossa máquina. Isso, obviamente, não é muito interessante no caso de uma aplicação Web, já que é esperado que, na Web, utilizemos dados da internet. Você pode conferir a primeira parte no seguinte link:

Nesta parte 2, esse é o problema que vamos resolver: vamos salvar os dados em uma base de dados remota e, em seguida, hospedar nossa aplicação. Nesse tutorial, vamos terminar de construir nossa API!

Salvando dados remotamente

Até agora, todos os nossos dados estavam sendo salvos localmente pela nossa aplicação, mas nós queremos que as mensagens enviadas pelo site sejam salvas permanentemente. Para isso, vamos usar um banco de dados remoto para guardar as informações. Nesse caso, vamos usar o MongoDB.

Entendendo o banco de dados remoto

Antes de qualquer coisa, vamos entender o que é esse banco de dados remoto: nós queremos que os dados da nossa aplicação fiquem salvos permanentemente para serem acessados a qualquer momento.

Para isso, nós vamos contratar um serviço que garanta para nós que nossos dados ficarão salvos permanentemente e também que nos dê uma forma de acessarmos esses dados. Este é o serviço que vamos contratar aqui.

Há empresas que oferecem esse serviço gratuitamente, dadas certas limitação. O MongoDB é uma dessas, e é ele que vamos usar aqui.

Preparando o banco

Antes de começarmos a enviar nossos dados, precisamos deixar nosso banco pronto para receber os dados.

Para preparar o banco, recomendo seguir este tutorial que ajuda a criar um cluster e prepará-lo para ser utilizado em uma aplicação NestJS:

Enviando dados

Se você seguiu o tutorial recomendado acima, você já tem o seu cluster pronto e já viu também que vamos precisar mexer no código que construímos anteriormente.

Para integrarmos nossa aplicação em NestJS com o banco do MongoDB, precisamos garantir que temos alguns pacotes instalados. Então, execute no seu terminal:

$ npm install --save @nestjs/mongoose mongoose
$ npm install --save-dev @types/mongoose

Primeiro, vamos fazer a importação no módulo principal da aplicação. Em app.module.ts, adicione uma importação contendo a referência de conexão fornecida pelo MongoDB. Onde estiver escrito <password>, substitua pela senha que você configurou e, em <dbname>, coloque o nome da base. O módulo da aplicação deve ficar assim ao final:

Feito isso, vamos trabalhar no nosso modelo. Até então, nossa aplicação tinha uma única entidade: Message. Porém, nosso banco de dado não conhece o tipo Message, temos que definir um tipo que o MongoDB reconheça. Vamos usar o decorador Schema() para fazer isso.

Esse decorador faz o mapeamento para uma base no MongoDB e define o formato dos documentos para o banco. Para utilizá-lo, lembre-se de importá-lo do pacote @nestjs/mongoose.

Vamos substituir a classe Message que havíamos criado anteriormente para criar aqui uma classe que estenda o tipo Document. Nela, vamos colocar os atributos da nossa classe. Os atributos são os mesmos que havíamos colocado anteriormente, mas, agora, eles vêm com o decorador Prop(); esse é o decorador responsável por definir uma propriedade do documento.

Por fim, vamos construir o Schema a partir da classe, usando SchemaFactory, também do pacote @nestjs/mongoose.

Nosso arquivo message.model.ts deve ficar assim ao final:

Antes de continuarmos a construir a lógica da aplicação, vamos informar ao módulo de Mensagens que temos um novo Schema, inserindo um novo item em imports. O módulo que construímos na parte 1 messages.module.ts deve ficar assim:

Agora que mudamos a classe base do nosso modelo, precisamos mudar, também, o restante da lógica da aplicação, começando pelo serviço. O serviço tinha, até então, duas funções básicas: uma para criar mensagens e, outra, para retornar todas as mensagens. Vamos substituir essas funções por dois métodos assíncronos: create(_:) e findAll().

Precisamos ter, no nosso serviço, um vetor de Message, mas, como esse modelo é um Schema, vamos inicializá-lo de forma diferente. No construtor do serviço, é passado o modelo Message da seguinte forma:

constructor(@InjectModel(Message.name) private messageModel: Model<Message>) {}

Vamos, então, implementar a função que cria mensagens:

async create(message: Message): Promise<Message> {    const createdMessage = new this.messageModel(message);    return createdMessage.save();}

A função é assíncrona, por isso escrevemos async antes dela. A função recebe uma Message e retorna não uma mensagem, mas uma promessa de mensagem, ou seja, nós esperamos que seja possível retornar a mensagem que iremos salvar no banco, por isso é uma Promisse. Criamos a mensagem a partir do modelo que foi passado no construtor do serviço e, por fim, salvamos. Ao salvar, retornamos a mensagem que foi salva (ou alguma outra resposta do banco para nós).

Depois de criar mensagens, precisamos buscá-las do banco. Vamos, agora, dar uma olhada na função de busca:

async findAll(): Promise<Message[]> {    return this.messageModel.find().exec();}

Novamente, a função é assíncrona e retorna a promessa de um vetor de mensagens, pois esperamos que esse seja o resultado da nossa busca ao servidor. O retorno dessa função é o que conseguimos retornar do nosso banco.

Por fim, o arquivo messages.service.ts deve ficar assim:

Agora precisamos mexer no nosso controller. O controller era responsável por cuidar das rotas da aplicação, então precisamos garantir que chamamos as funções certas do serviço.

Vamos primeiro alterar o método de POST. Esse método recebia todos os atributos separados e a instância de mensagem só era construída pelo serviço, mas, agora, vamos receber a mensagem completa no Body da requisição e passá-la para a função create(_:) do serviço:

@Post()postMessage(@Body() message: Message) {    return this.menssageService.create(message);}

No método de GET não mudamos muita coisa, exceto pelo nome da função, que, agora, é findAll():

@Get()getMenssages() {    return this.menssageService.findAll();}

Ao final, o controller deve ficar assim:

Feito isso, estamos prontos para rodar nossa aplicação!

Testando o banco

Vamos testar nosso banco da mesma forma que testamos da última vez. Vamos rodar a aplicação com o seguinte comando no terminal:

$ npm run start

Vamos voltar no Postman e fazer a mesma requisição que fizemos da última vez:

Requisição POST através do Postman

Insira a mensagem no formato JSON no Body da requisição. Tenha certeza de que as chaves tenham os mesmos nomes das propriedades da Message que criamos na aplicação. Envie a sua requisição.

Vamos dar uma olhada no nosso cluster no MongoDB. Se tudo estiver funcionando corretamente, você deve ver a mensagem enviada na seção Collections:

Mensagem criada no banco de dados

Ainda duvida? Tente fazer uma requisição GET pelo Postman, você verá o mesmo resultado por lá, no formato JSON.

Hospedando a aplicação

Muito bem! Já estamos guardando nossos dados em um banco, mas isso ainda não é suficiente para termos nosso site rodando. Por enquanto, a aplicação que construímos só roda na nossa máquina, o que claramente não é ideal para um site, já que a proposta de um site é que seu conteúdo seja acessado a partir de qualquer máquina em qualquer lugar.

Da mesma forma como contratamos um serviço que armazena os dados para nós em algum computador em algum lugar do mundo, precisamos contratar outro serviço que rode a nossa aplicação a todo momento e nos forneça uma forma para acessar a aplicação de qualquer lugar. Vamos, então, hospedar a aplicação.

Antes de qualquer coisa, precisamos fazer mais algumas alterações no nosso projeto:

No arquivo main.ts, precisamos habilitar CORS (Cross-Origin Resource Sharing) para a aplicação. O CORS usa cabeçalhos HTTP para informar ao navegador sobre as permissões de uma aplicação Web para acessar os recursos do servidor. Feito isso, vamos alterar a porta da requisição para permitir que usemos o valor de uma variável de ambiente PORT, caso haja uma.

Em seguida, precisamos garantir que a máquina que irá executar a nossa aplicação tenha NestJS instalado nela. No arquivo package.json, adicione em "dependencies":

"@nestjs/cli": "^7.0.0"

Aqui, nesse tutorial, vamos usar o Heroku para hospedar nossa aplicação:

www.heroku.com

Entre com sua conta e crie um novo app. Dê um nome para o app:

Neste exemplo, o nome do app é "br-message-app"

Em seguida, conecte o app ao código. Uma das formas de se fazer isso é conectando a um repositório do GitHub. Você pode usar o método de sua preferência.

Se você não sabe o que é GitHub, aqui no Zero e Umas tem um artigo bem legal sobre isso, vale a pena conferir:

Aqui podemos conectar o app com um repositório no GitHub

Ao conectar, encontramos algumas opções interessantes: podemos habilitar deploy automático ou fazer isso manualmente. Dar um deploy é tornar o software disponível para uso. Se habilitarmos para que o Heroku faça isso automaticamente a partir de uma branch, toda vez que houver uma alteração na branch, o app será atualizado. Mas também podemos fazer isso manualmente se quisermos.

Configurações de deploy

Na parte superior do site, clique em More > View logs para acompanhar a compilação e execução do projeto. Fique de olho para garantir que a aplicação seja executada sem erros!

Clique em View logs para acompanhar o progresso

Se tudo for executado sem problemas, clique em Open app para acessar sua aplicação. Será aberto um link: por este link nós acessamos nossa aplicação.

Insira /messages ao final do link para ver os dados que estão salvos no banco. Tente inserir o link no Postman e faça uma requisição POST, você deve poder ver os resultados da requisição nesse mesmo link.

Requisição POST através do Postman, usando o link da aplicação hospedada
Requisição GET através do Postman, usando o link da aplicação hospedada

Pronto! Construímos o Back-end do nosso site! Agora falta relacionarmos isso com a nossa interface.

Se você ainda não viu como a interface de uma aplicação Web é construída, vale a pena conferir nossos artigos sobre Front-end:

Referências

--

--