Criando um Bot do Telegram com Node.js
Tags: node, docker
Published: 2019-08-29 00:18:20

Olá, pessoal. Este é meu primeiro artigo aqui no Dev.to e nele vamos aprender a fazer um Bot do Telegram que monitora serviços web através de requisições HTTP. 

{% github thalesbruno/telegram-bot no-readme %}

As tecnologias utilizadas aqui foram o Node.js, o [Telegraf](https://telegraf.js.org/#/), que é um framework para construir Bots do Telegram em Node, o [Axios](https://github.com/axios/axios), um cliente HTTP em Javascript, e o Docker para dar um toque mais profissional, rs. Tem também o próprio Telegram, naturalmente, onde vamos iniciar a criação do Bot e vê-lo funcionando.

Acho que um bom ponto de partida é entrar no Telegram e criar nosso Bot. Poucas coisas na vida são mais fáceis que isso: basta procurar pela conta BotFather:

![BotFather](https://thepracticaldev.s3.amazonaws.com/i/hma51pv4cmt2b1donht3.png)

Ao iniciar uma conversa com o Pai dos Bots, são exibidos os comandos disponíveis para interagir com ele. Digitamos ou clicamos em `/newbot`, definimos um nome e em seguida um _username_, que deve obrigatoriamente terminar em 'bot'. Feito isso, nosso Bot estará criado e o BotFather disponibilizará um token de acesso que usaremos daqui pra frente para comandar nosso Bot. O BotFather nos aconselha a manter o token em segurança, já que ele pode ser usado por qualquer um para controlar nosso Bot.

![Bot Criado](https://thepracticaldev.s3.amazonaws.com/i/x5ycgcn4i81223k0euy7.png)


Vamos agora ao Node.js. Primeiro, criamos um diretório raiz pro projeto e dentro dele o `/src` onde ficará o código Javascript:

```bash
mkdir -p telegram-bot/src
cd telegram-bot
```

Então, inicializamos o projeto...

```bash
npm init -y
```

...e instalamos o módulo Telegraf

```bash
npm install telegraf
```

Agora as primeiras linhas de código. Criamos um arquivo `index.js` em `./telegram-bot/src` que será o _entrypoint_ do projeto:

```javascript
const Telegraf = require('telegraf')

const bot = new Telegraf(process.env.BOT_TOKEN)

bot.start((ctx) => ctx.reply("Hello world"))

bot.launch()
```

Nele, primeiro importamos o módulo Telegraf, então instanciamos um objeto bot, passando um único argumento, `process.env.BOT_TOKEN` (falaremos dele no próximo parágrafo). Em seguida, criamos nossa primeira "rota", `bot.start()`, aqui estabelecemos o que o Bot fará ao receber o comando `/start` (isso acontece ao iniciarmos pela primeira vez uma conversa com ele ou, após isso, digitarmos `/start` no chat). Nesta versão inicial de nosso código, ele apenas responderá com um "Hello world". Por fim, na última linha temos `bot.launch()` que inicializa o Bot.

Sobre o `process.env.BOT_TOKEN`, `process.env` retorna um objeto contendo as variáveis de ambiente do usuário, e destas estamos pegando a que nos interessa: a BOT_TOKEN. Mas para que isso funcione, precisamos criar a variável de ambiente BOT_TOKEN e atribuir a ela o token que o BotFather nos passou. Neste momento vamos apenas exportar nossa variável no terminal (Linux/MacOS) e, depois, quando subirmos nosso projeto em uma imagem Docker, vamos usar uma solução mais elegante. 

Então, no terminal basta executar:

```bash
export BOT_TOKEN=<O_TOKEN_QUE_O_BOTFATHER_NOS_PASSOU>
```

Nosso Bot já está pronto para ser executado! No diretório raiz, rodamos:

```bash
node src/index.js
```

No Telegram, já podemos interagir com nosso Bot:

![Bot start](https://thepracticaldev.s3.amazonaws.com/i/pe3dk6rppezzeultcazf.png)

O que precisamos implementar agora é uma rota `status` que chamará um módulo responsável por fazer a requisição ao serviço, retornando seu status que, por sua vez, gerará uma resposta de nosso Bot.

Vamos instalar o axios, que é um módulo cliente HTTP.

```bash
npm install axios
``` 

Novo arquivo`src/status.js`, bem simplezinho, checando o status da página inicial do Google:

```javascript
const axios = require('axios')

const status = async () => {
    try {
        return await axios.get('https://www.google.com/', { timeout: 30000 })
    } catch(error) {
        return error
    }
}

module.exports = status
```

No arquivo principal do projeto, `src/index.js`, vamos importar o módulo status e criar a rota que o chamará:

```javascript
const status = require('./status')

...

bot.command('status', async (ctx) => {

    try {
        const response = await status()

        if (response.status == 200) {
            await ctx.reply(`Google service: ✅`)
        } else {
            await ctx.reply(`Google service: ❌`)
        }

    } catch(error) {
        console.error(error)
    }
})
```

Projeto salvo, rodamos novamente o `node src/index.js` e vamos lá falar com nosso Bot:

![Bot status](https://thepracticaldev.s3.amazonaws.com/i/oa397tt7dgkrhcb73ow1.png)

Prontinho! Se o serviço Google tiver fora do ar, o que é meio difícil, ele vai responder com o ❌. 

Vamos fazer um ajuste no `package.json` para rodarmos nossa aplicação com  `npm start`:

```json
...

"scripts": {
    "start": "node src/index.js"
  }

...
```

Agora pra finalizar, vamos subir nosso projeto em Docker (e docker-compose)! Primeiro criamos um Dockerfile pra será o build de nossa imagem e depois um docker-compose.yml que subirá o serviço. São provavelmente os exemplos mais simples de [Dockerfile](https://docs.docker.com/engine/reference/builder/) e [docker-compose](https://docs.docker.com/compose/compose-file/) que vocês verão por aí:

Dockerfile
```docker
FROM node:12.7.0-alpine

WORKDIR /app
COPY . .
RUN ["npm", "install"]

ENV BOT_TOKEN=<PUT_YOUR_TELEGRAM_TOKEN_BOT_HERE>

ENTRYPOINT ["npm", "start"]
```

docker-compose.yml
```yml
version: '3'
services:
  bot:
    build: .
```

(Sim, é só isso). Lembrando que os dois arquivos devem estar na raiz do projeto, no Dockerfile colocamos ali em `ENV BOT_TOKEN` o mesmo token que já vínhamos usando.

Agora vamos colocar nosso Bot no ar novamente, mas dessa vez usando [docker-compose](https://docs.docker.com/compose/gettingstarted/):

```bash
docker-compose up -d
```
O `-d` é pra ele subir em background, liberando o promp do terminal. Pra parar o serviço é `docker-compose down`. Se fizer alguma modificação no código, é só rodar `docker-compose up -d --build` que ele subirá construindo uma nova imagem.

Com o Bot no ar em Docker, podemos ir no Telegram novamente e continuar interagindo com nosso Bot!

![Docker bot](https://thepracticaldev.s3.amazonaws.com/i/freeek44riannbdr9jrt.png)

Essa é uma versão bem simples e genérica, só pra ilustrar a implementação e o funcionamento. Pro artigo não ficar ainda maior, abstraí algumas explicações de códigos e comandos, mas coloquei os links com as referências de cada tecnologia. Qualquer dúvida é só dar um alô!