Interagindo com APIs REST a partir do Bash
1. Fundamentos: Ferramentas Essenciais para Requisições HTTP
O ecossistema Bash oferece duas ferramentas principais para comunicação HTTP: curl e wget. O curl é a escolha predominante para APIs REST devido ao seu suporte nativo a métodos HTTP, cabeçalhos customizados e tratamento granular de respostas.
# Sintaxe básica do curl
curl -X GET https://api.exemplo.com/usuarios
# Com opções comuns
curl -s -X POST https://api.exemplo.com/dados \
-H "Content-Type: application/json" \
-d '{"nome": "Maria"}'
# Salvando resposta em arquivo e extraindo tempo de resposta
curl -s -o resposta.json -w "Tempo: %{time_total}s\n" https://api.exemplo.com
O wget é mais adequado para downloads simples, mas não oferece controle fino sobre cabeçalhos e métodos. Antes de chamar APIs, teste conectividade com:
# Teste de conectividade
ping -c 1 api.exemplo.com > /dev/null 2>&1 && echo "OK" || echo "Falha"
nc -zv api.exemplo.com 443 2>&1 | grep -q "succeeded" && echo "Porta 443 aberta"
2. Estruturando Requisições: Cabeçalhos, Métodos e Corpo
Cada método HTTP tem finalidade específica. O curl utiliza a opção -X para especificar o método:
# GET - Consulta
curl -s https://api.exemplo.com/usuarios/123
# POST - Criação
curl -s -X POST https://api.exemplo.com/usuarios \
-H "Content-Type: application/json" \
-d '{"nome": "João", "email": "joao@email.com"}'
# PUT - Atualização completa
curl -s -X PUT https://api.exemplo.com/usuarios/123 \
-H "Content-Type: application/json" \
-d '{"nome": "João Silva", "email": "joao.silva@email.com"}'
# DELETE - Remoção
curl -s -X DELETE https://api.exemplo.com/usuarios/123
Cabeçalhos customizados são essenciais para autenticação e formatação:
# Autenticação Bearer
curl -s -H "Authorization: Bearer TOKEN_AQUI" https://api.exemplo.com/protegido
# Múltiplos cabeçalhos
curl -s -H "Content-Type: application/json" -H "Accept: application/json" \
-H "X-API-Key: chave123" https://api.exemplo.com/dados
Para envio de dados complexos:
# JSON no corpo
curl -s -X POST -H "Content-Type: application/json" \
-d '{"produto": "notebook", "quantidade": 2}' \
https://api.exemplo.com/pedidos
# Dados de formulário
curl -s -X POST --data-urlencode "nome=João" \
--data-urlencode "idade=30" \
https://api.exemplo.com/cadastro
# Upload de arquivo
curl -s -X POST -F "arquivo=@/home/usuario/documento.pdf" \
https://api.exemplo.com/upload
3. Autenticação e Tokens: Lidando com Segurança
Diferentes APIs exigem diferentes estratégias de autenticação. Veja as abordagens mais comuns:
# API Key via cabeçalho
API_KEY="sua_chave_secreta"
curl -s -H "X-API-Key: $API_KEY" https://api.exemplo.com/recurso
# API Key via query string (menos seguro)
curl -s "https://api.exemplo.com/recurso?api_key=$API_KEY"
# Autenticação Basic
curl -s --user "usuario:senha" https://api.exemplo.com/basico
# Codificação base64 manual
CREDENCIAIS=$(echo -n "usuario:senha" | base64)
curl -s -H "Authorization: Basic $CREDENCIAIS" https://api.exemplo.com/basico
Para tokens JWT, o fluxo típico envolve obter, armazenar e renovar:
# Obtenção do token
TOKEN=$(curl -s -X POST https://api.exemplo.com/auth \
-H "Content-Type: application/json" \
-d '{"usuario": "admin", "senha": "123456"}' | jq -r '.token')
# Uso do token em requisições subsequentes
curl -s -H "Authorization: Bearer $TOKEN" https://api.exemplo.com/dados
# Renovação automática (exemplo simplificado)
if curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $TOKEN" \
https://api.exemplo.com/verificar | grep -q "401"; then
echo "Token expirado. Renovando..."
TOKEN=$(curl -s -X POST https://api.exemplo.com/refresh \
-H "Authorization: Bearer $TOKEN" | jq -r '.token')
fi
4. Processamento de Respostas: JSON com jq e jo
O jq é indispensável para processar JSON no terminal. Com ele, você extrai campos específicos e formata saídas:
# Extrair campo específico
curl -s https://api.exemplo.com/usuarios/1 | jq '.nome'
# Selecionar múltiplos campos
curl -s https://api.exemplo.com/usuarios | jq '.[] | {nome, email}'
# Filtros condicionais
curl -s https://api.exemplo.com/usuarios | jq '.[] | select(.ativo == true)'
# Formatação personalizada
curl -s https://api.exemplo.com/usuarios | jq -r '.[] | "\(.id): \(.nome)"'
Para construir JSON dinamicamente, use jo ou printf:
# Construindo JSON com jo
DADOS=$(jo nome="Ana" idade=28 ativo=true)
curl -s -X POST -H "Content-Type: application/json" -d "$DADOS" \
https://api.exemplo.com/usuarios
# Alternativa com printf e jq
JSON=$(printf '{"nome": "%s", "idade": %d}' "Carlos" 35)
curl -s -X POST -H "Content-Type: application/json" -d "$JSON" \
https://api.exemplo.com/usuarios
Tratamento de erros com verificação de código HTTP:
HTTP_CODE=$(curl -s -o resposta.json -w "%{http_code}" https://api.exemplo.com/dados)
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
echo "Sucesso! Dados salvos em resposta.json"
cat resposta.json | jq '.'
else
echo "Erro $HTTP_CODE"
cat resposta.json | jq '.mensagem // "Sem detalhes"'
fi
5. Paginação e Iteração: Coletando Dados em Lotes
APIs frequentemente paginam resultados. Identifique o padrão e itere até esgotar:
# Paginação por página (GitHub Style)
PAGE=1
while true; do
RESPOSTA=$(curl -s "https://api.exemplo.com/itens?page=$PAGE&per_page=100")
QUANTIDADE=$(echo "$RESPOSTA" | jq '. | length')
[ "$QUANTIDADE" -eq 0 ] && break
echo "$RESPOSTA" | jq -c '.[]' >> todos_itens.json
echo "Página $PAGE: $QUANTIDADE itens"
((PAGE++))
done
# Paginação por cursor
CURSOR=""
while true; do
RESPOSTA=$(curl -s "https://api.exemplo.com/itens?cursor=$CURSOR")
echo "$RESPOSTA" | jq -c '.dados[]' >> todos_itens.json
CURSOR=$(echo "$RESPOSTA" | jq -r '.proximo_cursor // empty')
[ -z "$CURSOR" ] && break
sleep 0.5 # Controle de taxa
done
Respeite limites de taxa com --retry e sleeps:
# Requisição com retry automático
curl -s --retry 3 --retry-delay 5 --retry-max-time 30 \
https://api.exemplo.com/recurso
# Controle manual de taxa
for i in {1..10}; do
curl -s "https://api.exemplo.com/pagina/$i" >> resultados.json
sleep 2 # 2 segundos entre requisições
done
6. Scripts Modulares: Funções e Reutilização
Organize seu código em funções reutilizáveis para cada endpoint:
#!/bin/bash
# Configurações globais
API_BASE="https://api.exemplo.com/v1"
TOKEN="seu_token_aqui"
TIMEOUT=10
# Função genérica para requisições
api_request() {
local method=$1
local endpoint=$2
local data=$3
curl -s -X "$method" "$API_BASE$endpoint" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
${data:+-d "$data"} \
--max-time "$TIMEOUT"
}
# Funções específicas
get_users() {
api_request "GET" "/usuarios"
}
post_user() {
local nome=$1
local email=$2
local data=$(jo nome="$nome" email="$email")
api_request "POST" "/usuarios" "$data"
}
delete_user() {
local id=$1
api_request "DELETE" "/usuarios/$id"
}
# Uso
get_users | jq '.'
post_user "Maria" "maria@email.com"
delete_user 123
Para criar uma biblioteca pessoal, salve as funções em um arquivo separado:
# api_helper.sh
source api_helper.sh
get_users
7. Tratamento de Erros e Logging Robusto
Implemente verificações de erro e logging estruturado:
#!/bin/bash
LOG_DIR="./logs"
mkdir -p "$LOG_DIR"
log_request() {
local method=$1
local url=$2
local status=$3
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] $method $url -> $status" >> "$LOG_DIR/api.log"
}
api_call() {
local method=$1
local url=$2
local data=$3
local output=$(mktemp)
# Executa requisição
http_code=$(curl -s -o "$output" -w "%{http_code}" \
-X "$method" "$url" \
${data:+-d "$data"} \
-H "Content-Type: application/json")
log_request "$method" "$url" "$http_code"
# Tratamento de erro
if [ "$http_code" -ge 400 ]; then
echo "Erro $http_code:" >&2
cat "$output" | jq '.' >&2
rm "$output"
return 1
fi
cat "$output"
rm "$output"
}
# Estratégia de retry com backoff exponencial
retry_api_call() {
local max_retries=5
local attempt=1
local wait=2
while [ $attempt -le $max_retries ]; do
if api_call "$@"; then
return 0
fi
echo "Tentativa $attempt falhou. Aguardando ${wait}s..." >&2
sleep $wait
wait=$((wait * 2))
((attempt++))
done
echo "Falha após $max_retries tentativas" >&2
return 1
}
8. Casos Práticos: Automação de Tarefas Reais
Monitoramento de status de serviço com GitHub API:
#!/bin/bash
check_github_status() {
local status=$(curl -s https://www.githubstatus.com/api/v2/status.json | \
jq -r '.status.indicator')
case "$status" in
"none") echo "✅ GitHub operacional" ;;
"minor") echo "⚠️ GitHub com problemas menores" ;;
"major") echo "🔴 GitHub com problemas graves" ;;
*) echo "❌ Não foi possível verificar status" ;;
esac
}
check_github_status
Envio de notificação para Slack via webhook:
#!/bin/bash
WEBHOOK_URL="https://hooks.slack.com/services/T123/B456/SEU_TOKEN"
send_slack_notification() {
local message=$1
local channel=${2:-#geral}
local payload=$(jo text="$message" channel="$channel")
curl -s -X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "$payload" > /dev/null
echo "Notificação enviada para $channel"
}
send_slack_notification "🚀 Deploy realizado com sucesso!" "#deploy"
Backup de dados de API para CSV:
#!/bin/bash
API_URL="https://api.exemplo.com/usuarios"
CSV_FILE="backup_usuarios_$(date +%Y%m%d).csv"
echo "ID,Nome,Email,DataCadastro" > "$CSV_FILE"
curl -s "$API_URL" | jq -r '.[] | [.id, .nome, .email, .data_cadastro] | @csv' \
>> "$CSV_FILE"
echo "Backup concluído: $(wc -l < "$CSV_FILE") registros em $CSV_FILE"
Referências
- Documentação oficial do curl — Manual completo com todas as opções do curl para requisições HTTP
- jq Manual (stedolan.github.io) — Guia de referência do processador JSON jq, essencial para parsing de respostas de API
- GitHub REST API Documentation — Exemplos práticos de autenticação, paginação e rate limiting com APIs reais
- Advanced Bash-Scripting Guide: Chapter 19 - I/O Redirection — Tutorial avançado sobre redirecionamento e manipulação de saída em scripts Bash
- Shell Scripting para Automação de APIs (DigitalOcean Tutorial) — Tutorial prático cobrindo curl, jq e automação de APIs REST no terminal
- jo - JSON Output from a Shell — Repositório oficial da ferramenta jo para construção de JSON a partir do shell
- OpenAPI Specification — Especificação padrão para documentação de APIs REST, útil para entender estruturas de requisição e resposta