0.0
No release in over 3 years
Uma gem Ruby para consumir facilmente a Evolution API, permitindo integração com WhatsApp através de uma API REST simples e poderosa.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Development

~> 0.14
~> 13.0
~> 3.12
~> 1.50
~> 6.1
~> 3.18
~> 0.9

Runtime

 Project Readme

Evolution API Ruby Client

Ruby Version Gem Version License GitHub Build Status

Uma gem Ruby elegante e poderosa para consumir a Evolution API, permitindo integração fácil com WhatsApp através de uma API REST simples e robusta.

🚀 Características

  • Interface Ruby Nativa: API limpa e intuitiva
  • Suporte Completo: Todos os endpoints da Evolution API
  • Tratamento de Erros: Exceções personalizadas e informativas
  • Configuração Flexível: Sistema de configuração robusto
  • Retry Automático: Tentativas automáticas em caso de falha
  • Validação: Validação de dados com Dry::Validation
  • Documentação Completa: YARD documentation
  • Testes Abrangentes: RSpec com VCR para testes confiáveis

📦 Instalação

Adicione a gem ao seu Gemfile:

gem 'evolution_api'

E execute:

bundle install

Ou instale diretamente:

gem install evolution_api

🚂 Integração com Rails

Instalação em Projetos Rails

  1. Adicione a gem ao seu Gemfile:
# Gemfile
gem 'evolution_api'
  1. Execute o bundle install:
bundle install
  1. Configure a gem no initializer:
# config/initializers/evolution_api.rb
EvolutionApi.configure do |config|
  config.base_url = Rails.application.credentials.evolution_api[:base_url] || "http://localhost:8080"
  config.api_key = Rails.application.credentials.evolution_api[:api_key]
  config.timeout = 30
  config.retry_attempts = 3
  config.retry_delay = 1
end
  1. Configure as credenciais (Rails 5.2+):
rails credentials:edit

Adicione no arquivo de credenciais:

evolution_api:
  base_url: "https://sua-evolution-api.com"
  api_key: "sua_api_key_aqui"

Exemplo de Controller Rails

# app/controllers/whatsapp_controller.rb
class WhatsAppController < ApplicationController
  before_action :set_client

  def send_message
    begin
      response = @client.send_text_message(
        params[:instance_name],
        params[:phone_number],
        params[:message]
      )
      
      render json: { success: true, data: response }
    rescue EvolutionApi::Error => e
      render json: { success: false, error: e.message }, status: :unprocessable_entity
    end
  end

  def list_instances
    instances = @client.list_instances
    render json: { instances: instances }
  end

  def create_instance
    response = @client.create_instance(params[:instance_name], {
      qrcode: true,
      webhook: webhook_url
    })
    
    render json: { success: true, data: response }
  end

  private

  def set_client
    @client = EvolutionApi.client
  end

  def webhook_url
    "#{request.base_url}/webhooks/whatsapp"
  end
end

Exemplo de Model Rails

# app/models/whatsapp_message.rb
class WhatsAppMessage < ApplicationRecord
  validates :instance_name, presence: true
  validates :phone_number, presence: true
  validates :message_type, presence: true, inclusion: { in: %w[text image audio video document] }
  validates :content, presence: true

  after_create :send_to_whatsapp

  private

  def send_to_whatsapp
    client = EvolutionApi.client
    
    case message_type
    when 'text'
      client.send_text_message(instance_name, phone_number, content)
    when 'image'
      client.send_image_message(instance_name, phone_number, content, caption)
    when 'audio'
      client.send_audio_message(instance_name, phone_number, content)
    when 'video'
      client.send_video_message(instance_name, phone_number, content, caption)
    when 'document'
      client.send_document_message(instance_name, phone_number, content, caption)
    end
  rescue EvolutionApi::Error => e
    update(status: 'failed', error_message: e.message)
  end
end

Exemplo de Service Object

# app/services/whatsapp_service.rb
class WhatsAppService
  def initialize(instance_name = nil)
    @client = EvolutionApi.client
    @instance_name = instance_name || Rails.application.credentials.evolution_api[:default_instance]
  end

  def send_bulk_messages(phone_numbers, message)
    results = []
    
    phone_numbers.each do |phone|
      begin
        response = @client.send_text_message(@instance_name, phone, message)
        results << { phone: phone, success: true, response: response }
      rescue EvolutionApi::Error => e
        results << { phone: phone, success: false, error: e.message }
      end
    end
    
    results
  end

  def broadcast_message(message, options = {})
    contacts = @client.get_contacts(@instance_name)
    
    contacts.each do |contact|
      next if options[:exclude_numbers]&.include?(contact['id'])
      
      @client.send_text_message(@instance_name, contact['id'], message)
      sleep(options[:delay] || 1) # Evita rate limiting
    end
  end

  def instance_status
    @client.get_instance(@instance_name)
  end

  def is_connected?
    status = instance_status
    status['status'] == 'open'
  end
end

Exemplo de Job para Processamento Assíncrono

# app/jobs/whatsapp_message_job.rb
class WhatsAppMessageJob < ApplicationJob
  queue_as :whatsapp

  def perform(instance_name, phone_number, message, message_type = 'text')
    client = EvolutionApi.client
    
    case message_type
    when 'text'
      client.send_text_message(instance_name, phone_number, message)
    when 'image'
      client.send_image_message(instance_name, phone_number, message[:url], message[:caption])
    when 'audio'
      client.send_audio_message(instance_name, phone_number, message[:url])
    when 'video'
      client.send_video_message(instance_name, phone_number, message[:url], message[:caption])
    when 'document'
      client.send_document_message(instance_name, phone_number, message[:url], message[:caption])
    end
  rescue EvolutionApi::Error => e
    Rails.logger.error "WhatsApp message failed: #{e.message}"
    raise e
  end
end

Exemplo de Webhook Controller

# app/controllers/webhooks/whatsapp_controller.rb
class Webhooks::WhatsappController < ApplicationController
  skip_before_action :verify_authenticity_token
  
  def receive
    case params[:event]
    when 'connection.update'
      handle_connection_update
    when 'message.upsert'
      handle_message_upsert
    when 'qr.update'
      handle_qr_update
    end
    
    head :ok
  end

  private

  def handle_connection_update
    instance_name = params[:instance]
    status = params[:data][:status]
    
    Rails.logger.info "WhatsApp instance #{instance_name} status: #{status}"
    
    # Atualizar status no banco de dados
    instance = WhatsAppInstance.find_by(name: instance_name)
    instance&.update(status: status)
  end

  def handle_message_upsert
    message_data = params[:data]
    instance_name = params[:instance]
    
    # Processar mensagem recebida
    message = Message.create!(
      instance_name: instance_name,
      phone_number: message_data[:key][:remoteJid],
      message_type: detect_message_type(message_data[:message]),
      content: extract_message_content(message_data[:message]),
      from_me: message_data[:key][:fromMe],
      timestamp: Time.at(message_data[:messageTimestamp])
    )
    
    # Processar automaticamente se necessário
    AutoReplyService.new(message).process if should_auto_reply?(message)
  end

  def handle_qr_update
    instance_name = params[:instance]
    qr_code = params[:data][:qrcode]
    
    # Salvar QR code para exibição
    Rails.cache.write("whatsapp_qr_#{instance_name}", qr_code, expires_in: 2.minutes)
  end

  def detect_message_type(message)
    return 'text' if message[:conversation] || message[:extendedTextMessage]
    return 'image' if message[:imageMessage]
    return 'audio' if message[:audioMessage]
    return 'video' if message[:videoMessage]
    return 'document' if message[:documentMessage]
    return 'location' if message[:locationMessage]
    return 'contact' if message[:contactMessage]
    'unknown'
  end

  def extract_message_content(message)
    return message[:conversation] if message[:conversation]
    return message[:extendedTextMessage][:text] if message[:extendedTextMessage]
    return message[:imageMessage][:url] if message[:imageMessage]
    return message[:audioMessage][:url] if message[:audioMessage]
    return message[:videoMessage][:url] if message[:videoMessage]
    return message[:documentMessage][:url] if message[:documentMessage]
    nil
  end

  def should_auto_reply?(message)
    !message.from_me && message.message_type == 'text'
  end
end

Configuração de Rotas

# config/routes.rb
Rails.application.routes.draw do
  # Rotas para WhatsApp
  resources :whatsapp, only: [:index] do
    collection do
      post :send_message
      get :list_instances
      post :create_instance
      get :qr_code/:instance_name, action: :qr_code, as: :qr_code
    end
  end

  # Webhook para receber mensagens
  post 'webhooks/whatsapp', to: 'webhooks/whatsapp#receive'
end

Exemplo de View com Stimulus

<!-- app/views/whatsapp/index.html.erb -->
<div class="whatsapp-dashboard" data-controller="whatsapp">
  <h1>WhatsApp Dashboard</h1>
  
  <div class="instances">
    <h2>Instâncias</h2>
    <div data-whatsapp-target="instancesList">
      <!-- Será preenchido via Stimulus -->
    </div>
    
    <button data-action="click->whatsapp#createInstance">Nova Instância</button>
  </div>
  
  <div class="qr-code" data-whatsapp-target="qrCode">
    <!-- QR Code será exibido aqui -->
  </div>
  
  <div class="send-message">
    <h2>Enviar Mensagem</h2>
    <form data-action="submit->whatsapp#sendMessage">
      <select data-whatsapp-target="instanceSelect" required>
        <option value="">Selecione uma instância</option>
      </select>
      
      <input type="tel" data-whatsapp-target="phoneInput" placeholder="Número (ex: 5511999999999)" required>
      
      <textarea data-whatsapp-target="messageInput" placeholder="Mensagem" required></textarea>
      
      <button type="submit">Enviar</button>
    </form>
  </div>
  
  <!-- Área para notificações -->
  <div data-whatsapp-target="notifications"></div>
</div>

Controller Stimulus

// app/javascript/controllers/whatsapp_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["instancesList", "instanceSelect", "phoneInput", "messageInput", "qrCode", "notifications"]

  connect() {
    this.loadInstances()
  }

  async loadInstances() {
    try {
      const response = await fetch('/whatsapp/list_instances')
      const data = await response.json()
      
      this.updateInstancesList(data.instances)
      this.updateInstanceSelect(data.instances)
    } catch (error) {
      this.showNotification('Erro ao carregar instâncias: ' + error.message, 'error')
    }
  }

  updateInstancesList(instances) {
    this.instancesListTarget.innerHTML = instances.map(instance => `
      <div class="instance">
        <strong>${instance.instance}</strong>
        <span class="status ${instance.status}">${instance.status}</span>
        <button data-action="click->whatsapp#connectInstance" data-instance="${instance.instance}">
          Conectar
        </button>
      </div>
    `).join('')
  }

  updateInstanceSelect(instances) {
    this.instanceSelectTarget.innerHTML = '<option value="">Selecione uma instância</option>' +
      instances.map(instance => `
        <option value="${instance.instance}">${instance.instance} (${instance.status})</option>
      `).join('')
  }

  async sendMessage(event) {
    event.preventDefault()
    
    const formData = new FormData(event.target)
    
    try {
      const response = await fetch('/whatsapp/send_message', {
        method: 'POST',
        body: formData,
        headers: {
          'X-CSRF-Token': document.querySelector('[name="csrf-token"]').content
        }
      })
      
      const data = await response.json()
      
      if (data.success) {
        this.showNotification('Mensagem enviada com sucesso!', 'success')
        event.target.reset()
      } else {
        this.showNotification('Erro ao enviar mensagem: ' + data.error, 'error')
      }
    } catch (error) {
      this.showNotification('Erro de conexão: ' + error.message, 'error')
    }
  }

  async createInstance() {
    const instanceName = prompt('Nome da instância:')
    if (!instanceName) return
    
    try {
      const response = await fetch('/whatsapp/create_instance', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-CSRF-Token': document.querySelector('[name="csrf-token"]').content
        },
        body: JSON.stringify({ instance_name: instanceName })
      })
      
      const data = await response.json()
      
      if (data.success) {
        this.showNotification('Instância criada! Verifique o QR Code.', 'success')
        this.loadInstances()
      } else {
        this.showNotification('Erro ao criar instância: ' + data.error, 'error')
      }
    } catch (error) {
      this.showNotification('Erro de conexão: ' + error.message, 'error')
    }
  }

  async connectInstance(event) {
    const instanceName = event.currentTarget.dataset.instance
    
    try {
      const response = await fetch('/whatsapp/connect_instance', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-CSRF-Token': document.querySelector('[name="csrf-token"]').content
        },
        body: JSON.stringify({ instance_name: instanceName })
      })
      
      const data = await response.json()
      
      if (data.success && data.qr_code) {
        this.showQRCode(data.qr_code)
        this.showNotification('QR Code gerado! Escaneie com o WhatsApp.', 'info')
      } else {
        this.showNotification('Erro ao conectar instância: ' + data.error, 'error')
      }
    } catch (error) {
      this.showNotification('Erro de conexão: ' + error.message, 'error')
    }
  }

  showQRCode(qrCode) {
    this.qrCodeTarget.innerHTML = `
      <h3>QR Code para Conectar</h3>
      <img src="${qrCode}" alt="QR Code WhatsApp" style="max-width: 300px;">
    `
  }

  showNotification(message, type) {
    const notification = document.createElement('div')
    notification.className = `alert alert-${type === 'success' ? 'success' : type === 'error' ? 'danger' : 'info'} alert-dismissible fade show`
    notification.innerHTML = `
      ${message}
      <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
    `
    
    this.notificationsTarget.appendChild(notification)
    
    // Auto-remove após 5 segundos
    setTimeout(() => {
      notification.remove()
    }, 5000)
  }
}

Configuração do Stimulus

Certifique-se de que o Stimulus está configurado no seu projeto Rails:

# Se estiver usando importmap (Rails 7+)
bin/rails stimulus:install

# Se estiver usando esbuild/webpack
yarn add @hotwired/stimulus

Controller Rails com Turbo Streams

# app/controllers/whatsapp_controller.rb
class WhatsappController < ApplicationController
  def index
    # Renderiza a view principal
  end

  def list_instances
    instances = EvolutionApi::Client.new.list_instances
    
    respond_to do |format|
      format.json { render json: { instances: instances } }
      format.turbo_stream do
        render turbo_stream: turbo_stream.replace(
          "instances-list",
          partial: "instances_list",
          locals: { instances: instances }
        )
      end
    end
  end

  def send_message
    result = WhatsappService.new.send_message(message_params)
    
    respond_to do |format|
      format.json { render json: result }
      format.turbo_stream do
        if result[:success]
          render turbo_stream: [
            turbo_stream.replace("message-form", partial: "message_form"),
            turbo_stream.append("notifications", partial: "notification", locals: { 
              message: "Mensagem enviada com sucesso!", 
              type: "success" 
            })
          ]
        else
          render turbo_stream: turbo_stream.append("notifications", partial: "notification", locals: { 
            message: result[:error], 
            type: "error" 
          })
        end
      end
    end
  end

  def create_instance
    result = WhatsappService.new.create_instance(params[:instance_name])
    
    respond_to do |format|
      format.json { render json: result }
      format.turbo_stream do
        if result[:success]
          render turbo_stream: [
            turbo_stream.replace("instances-list", partial: "instances_list", locals: { instances: result[:instances] }),
            turbo_stream.append("notifications", partial: "notification", locals: { 
              message: "Instância criada com sucesso!", 
              type: "success" 
            })
          ]
        else
          render turbo_stream: turbo_stream.append("notifications", partial: "notification", locals: { 
            message: result[:error], 
            type: "error" 
          })
        end
      end
    end
  end

  def connect_instance
    result = WhatsappService.new.connect_instance(params[:instance_name])
    
    respond_to do |format|
      format.json { render json: result }
      format.turbo_stream do
        if result[:success]
          render turbo_stream: turbo_stream.replace("qr-code", partial: "qr_code", locals: { qr_code: result[:qr_code] })
        else
          render turbo_stream: turbo_stream.append("notifications", partial: "notification", locals: { 
            message: result[:error], 
            type: "error" 
          })
        end
      end
    end
  end

  private

  def message_params
    params.permit(:instance_name, :phone_number, :message)
  end
end

Partials para Turbo Streams

<!-- app/views/whatsapp/_instances_list.html.erb -->
<div id="instances-list">
  <% instances.each do |instance| %>
    <div class="instance">
      <strong><%= instance.instance %></strong>
      <span class="status <%= instance.status %>"><%= instance.status %></span>
      <button data-action="click->whatsapp#connectInstance" data-instance="<%= instance.instance %>">
        Conectar
      </button>
    </div>
  <% end %>
</div>
<!-- app/views/whatsapp/_notification.html.erb -->
<div class="alert alert-<%= type == 'success' ? 'success' : type == 'error' ? 'danger' : 'info' %> alert-dismissible fade show" role="alert">
  <%= message %>
  <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<!-- app/views/whatsapp/_qr_code.html.erb -->
<div id="qr-code">
  <h3>QR Code para Conectar</h3>
  <img src="<%= qr_code %>" alt="QR Code WhatsApp" style="max-width: 300px;">
</div>

## ⚙️ Configuração

### Configuração Básica

```ruby
require 'evolution_api'

EvolutionApi.configure do |config|
  config.base_url = "http://localhost:8080"  # URL da sua Evolution API
  config.api_key = "sua_api_key_aqui"        # Sua chave API (opcional)
  config.timeout = 30                         # Timeout em segundos
  config.retry_attempts = 3                   # Número de tentativas
  config.retry_delay = 1                      # Delay entre tentativas (segundos)
end

Configuração Avançada

EvolutionApi.configure do |config|
  # Configurações básicas
  config.base_url = "https://api.evolution.com"
  config.api_key = "sua_chave_api"
  
  # Configurações de webhook
  config.webhook_url = "https://seu-site.com/webhook"
  config.webhook_events = ["connection.update", "message.upsert"]
  
  # Configurações de log
  config.logger = Rails.logger
  config.log_level = :info
  
  # Configurações de cache
  config.cache_enabled = true
  config.cache_ttl = 300 # 5 minutos
end

🎯 Uso Básico

Inicialização do Cliente

# Usando o cliente global
client = EvolutionApi.client

# Ou criando uma instância personalizada
client = EvolutionApi::Client.new

Gerenciamento de Instâncias

# Listar todas as instâncias
instances = client.list_instances

# Criar uma nova instância
client.create_instance("minha_instancia", {
  qrcode: true,
  webhook: "https://seu-site.com/webhook"
})

# Conectar uma instância
client.connect_instance("minha_instancia")

# Obter QR Code para conexão
qr_code = client.get_qr_code("minha_instancia")

# Verificar status da instância
instance_info = client.get_instance("minha_instancia")
puts "Status: #{instance_info['status']}"

# Desconectar instância
client.disconnect_instance("minha_instancia")

# Remover instância
client.delete_instance("minha_instancia")

Envio de Mensagens

# Mensagem de texto
client.send_text_message("minha_instancia", "5511999999999", "Olá! Como vai?")

# Mensagem de imagem
client.send_image_message(
  "minha_instancia", 
  "5511999999999", 
  "https://exemplo.com/imagem.jpg",
  "Legenda da imagem"
)

# Mensagem de áudio
client.send_audio_message(
  "minha_instancia", 
  "5511999999999", 
  "https://exemplo.com/audio.mp3"
)

# Mensagem de vídeo
client.send_video_message(
  "minha_instancia", 
  "5511999999999", 
  "https://exemplo.com/video.mp4",
  "Descrição do vídeo"
)

# Documento
client.send_document_message(
  "minha_instancia", 
  "5511999999999", 
  "https://exemplo.com/documento.pdf",
  "Descrição do documento"
)

# Localização
client.send_location_message(
  "minha_instancia", 
  "5511999999999", 
  -23.5505, 
  -46.6333, 
  "São Paulo, SP"
)

# Contato
client.send_contact_message(
  "minha_instancia", 
  "5511999999999", 
  "5511888888888", 
  "João Silva"
)

Mensagens Interativas

# Mensagem com botões
buttons = [
  { id: "btn1", body: "Opção 1" },
  { id: "btn2", body: "Opção 2" },
  { id: "btn3", body: "Opção 3" }
]

client.send_button_message(
  "minha_instancia",
  "5511999999999",
  "Título da mensagem",
  "Descrição da mensagem",
  buttons
)

# Lista de opções
sections = [
  {
    title: "Seção 1",
    rows: [
      { id: "1", title: "Item 1", description: "Descrição 1" },
      { id: "2", title: "Item 2", description: "Descrição 2" }
    ]
  }
]

client.send_list_message(
  "minha_instancia",
  "5511999999999",
  "Título da lista",
  "Descrição da lista",
  sections
)

Gerenciamento de Chats

# Obter todos os chats
chats = client.get_chats("minha_instancia")

# Obter mensagens de um chat
messages = client.get_messages("minha_instancia", "5511999999999", {
  limit: 50,
  cursor: "cursor_para_paginacao"
})

# Marcar mensagens como lidas
client.mark_messages_as_read("minha_instancia", "5511999999999")

# Arquivar chat
client.archive_chat("minha_instancia", "5511999999999")

# Desarquivar chat
client.unarchive_chat("minha_instancia", "5511999999999")

# Deletar chat
client.delete_chat("minha_instancia", "5511999999999")

Gerenciamento de Contatos

# Obter todos os contatos
contacts = client.get_contacts("minha_instancia")

# Obter informações de um contato específico
contact = client.get_contact("minha_instancia", "5511999999999")

# Verificar se um número existe no WhatsApp
result = client.check_number("minha_instancia", "5511999999999")
puts "Número existe: #{result['exists']}"

# Bloquear contato
client.block_contact("minha_instancia", "5511999999999")

# Desbloquear contato
client.unblock_contact("minha_instancia", "5511999999999")

Configuração de Webhooks

# Configurar webhook
client.set_webhook(
  "minha_instancia",
  "https://seu-site.com/webhook",
  ["connection.update", "message.upsert"]
)

# Obter configuração do webhook
webhook_config = client.get_webhook("minha_instancia")

# Remover webhook
client.delete_webhook("minha_instancia")

🎨 Uso com Classes Auxiliares

Usando a Classe Instance

# Criar uma instância gerenciada
instance = EvolutionApi::Instance.new("minha_instancia", client)

# Verificar se está conectada
if instance.connected?
  puts "Instância conectada!"
  
  # Enviar mensagem
  instance.send_text("5511999999999", "Olá!")
  
  # Obter chats
  chats = instance.chats
  
  # Obter contatos
  contacts = instance.contacts
else
  puts "Instância não conectada"
  qr_code = instance.qr_code
end

Trabalhando com Mensagens

# Obter mensagens e processar
messages_data = client.get_messages("minha_instancia", "5511999999999")
messages = messages_data.map { |msg| EvolutionApi::Message.new(msg, "minha_instancia") }

messages.each do |message|
  case message.type
  when "text"
    puts "Texto: #{message.text}"
  when "image"
    puts "Imagem: #{message.image['url']}"
  when "audio"
    puts "Áudio: #{message.audio['url']}"
  end
  
  puts "De: #{message.from}"
  puts "Enviada por mim: #{message.from_me?}"
  puts "Grupo: #{message.group?}"
  puts "Timestamp: #{message.timestamp}"
end

Trabalhando com Chats

# Obter chats e processar
chats_data = client.get_chats("minha_instancia")
chats = chats_data.map { |chat| EvolutionApi::Chat.new(chat, "minha_instancia") }

chats.each do |chat|
  puts "Chat: #{chat.name}"
  puts "Número: #{chat.number}"
  puts "Grupo: #{chat.group?}"
  puts "Não lidas: #{chat.unread_count}"
  puts "Arquivado: #{chat.archived?}"
end

Trabalhando com Contatos

# Obter contatos e processar
contacts_data = client.get_contacts("minha_instancia")
contacts = contacts_data.map { |contact| EvolutionApi::Contact.new(contact, "minha_instancia") }

contacts.each do |contact|
  puts "Nome: #{contact.display_name}"
  puts "Número: #{contact.number}"
  puts "Business: #{contact.business?}"
  puts "Verificado: #{contact.verified?}"
end

🚨 Tratamento de Erros

A gem fornece exceções específicas para diferentes tipos de erro:

begin
  client.send_text_message("instancia_inexistente", "5511999999999", "Olá!")
rescue EvolutionApi::NotFoundError => e
  puts "Instância não encontrada: #{e.message}"
rescue EvolutionApi::AuthenticationError => e
  puts "Erro de autenticação: #{e.message}"
rescue EvolutionApi::ValidationError => e
  puts "Erro de validação: #{e.message}"
  puts "Detalhes: #{e.errors}"
rescue EvolutionApi::RateLimitError => e
  puts "Rate limit excedido: #{e.message}"
rescue EvolutionApi::ServerError => e
  puts "Erro do servidor: #{e.message}"
rescue EvolutionApi::ConnectionError => e
  puts "Erro de conexão: #{e.message}"
rescue EvolutionApi::TimeoutError => e
  puts "Timeout: #{e.message}"
end

🧪 Testes

Executar Testes

# Executar todos os testes
bundle exec rspec

# Executar testes com coverage
bundle exec rspec --format documentation

# Executar testes específicos
bundle exec rspec spec/evolution_api/client_spec.rb

Exemplo de Teste

require 'spec_helper'

RSpec.describe EvolutionApi::Client do
  let(:client) { described_class.new }

  describe '#list_instances' do
    it 'returns list of instances' do
      VCR.use_cassette('list_instances') do
        response = client.list_instances
        expect(response).to be_an(Array)
      end
    end
  end

  describe '#send_text_message' do
    it 'sends text message successfully' do
      VCR.use_cassette('send_text_message') do
        response = client.send_text_message(
          'test_instance',
          '5511999999999',
          'Test message'
        )
        expect(response['status']).to eq('success')
      end
    end
  end
end

📚 Documentação

A documentação completa está disponível em:

Para gerar a documentação localmente:

bundle exec yard doc
bundle exec yard server

🤝 Contribuindo

  1. Faça um fork do projeto
  2. Crie uma branch para sua feature (git checkout -b feature/AmazingFeature)
  3. Commit suas mudanças (git commit -m 'Add some AmazingFeature')
  4. Push para a branch (git push origin feature/AmazingFeature)
  5. Abra um Pull Request

Padrões de Código

# Verificar estilo do código
bundle exec rubocop

# Corrigir automaticamente
bundle exec rubocop -a

# Verificar apenas arquivos modificados
bundle exec rubocop --only-guide-cops

📄 Licença

Este projeto está licenciado sob a Licença MIT - veja o arquivo LICENSE.txt para detalhes.

🆘 Suporte

🙏 Agradecimentos


Desenvolvido com ❤️ para a comunidade Ruby