Curso de Python / Consultar uma API HTTP e validar a resposta JSON
Uma API HTTP recebe requisições e devolve um status e dados de resposta. Em Python, confira separadamente a comunicação, o tempo de espera, o tamanho da resposta e a estrutura do JSON antes de usar seus valores.
Entender protocolo, endereço e formato
API é uma interface de programação de aplicações. HTTP é o protocolo de requisição e resposta; a URL identifica o recurso solicitado; JSON é um dos formatos possíveis para o corpo da resposta. Um status de sucesso não garante que o corpo contenha os campos e tipos exigidos pelo programa.
Esta prática usa uma resposta local, sob seu controle, para evitar depender de alterações em uma API externa. O cliente soma despesas recebidas pela rede, mas o servidor é apenas um recurso de teste: http.server não é uma recomendação de implantação em produção. Consulte a documentação do servidor HTTP da biblioteca padrão.
Ao adaptar o cliente a um serviço real, consulte a documentação específica de HTTPS, autenticação, limites de requisição e formato dos dados. Não desative a verificação de certificados para fazer uma requisição funcionar. A estrutura JSON também precisa ser validada, como na aula sobre leitura e gravação de JSON.
Preparar a resposta e iniciar o servidor local
Crie uma pasta vazia para o exercício. Salve um arquivo chamado expenses.json, em UTF-8, com este conteúdo completo:
[{"id":"e1","name":"coffee","amount":3500},{"id":"e2","name":"lunch","amount":8000}]
No primeiro terminal, selecione o ambiente virtual do projeto, entre nessa pasta e execute:
python -m http.server 8000 --bind 127.0.0.1
Deixe esse terminal aberto enquanto roda o cliente em outro. O endereço 127.0.0.1 é o loopback, usado para acessar o próprio computador. A opção --bind 127.0.0.1 limita a escuta a essa interface. Use apenas arquivos descartáveis nessa pasta: o servidor pode disponibilizar os arquivos do diretório servido, não somente o JSON.
Se a porta 8000 já estiver ocupada, escolha outra, como 8001, no comando do servidor e altere também a URL passada ao cliente. Um servidor iniciado na pasta errada pode funcionar normalmente e ainda devolver 404 para o arquivo procurado. Não é necessário instalar pacotes adicionais. No macOS ou Ubuntu, fora de um ambiente virtual, use python3 se esse for o nome do interpretador.
Executar o cliente e conferir os totais
Salve o programa completo abaixo como fetch_expenses.py, em UTF-8, na pasta de prática.
import json
import sys
from urllib.request import urlopen
from urllib.error import HTTPError, URLError
url = sys.argv[1]
try:
with urlopen(url, timeout=5) as response:
if response.status != 200:
raise ValueError("unexpected status")
raw = response.read(1_000_001)
if len(raw) > 1_000_000:
raise ValueError("response too large")
data = json.loads(raw.decode("utf-8"))
except (HTTPError, URLError, TimeoutError, UnicodeError, ValueError) as error:
raise SystemExit(f"request failed: {type(error).__name__}")
if not isinstance(data, list):
raise SystemExit("expected a list")
total = 0
for row in data:
if not isinstance(row, dict) or type(row.get("amount")) is not int or row["amount"] < 0:
raise SystemExit("invalid record")
total += row["amount"]
print("records:", len(data))
print("total:", total)
No segundo terminal, selecione o mesmo ambiente, entre na pasta e execute:
python fetch_expenses.py http://127.0.0.1:8000/expenses.json
A saída esperada contém records: 2 e total: 11500, uma linha para cada informação. Os rótulos significam quantidade de registros e soma dos valores. O cliente usa o primeiro argumento como URL: omiti-lo causa IndexError antes do bloco de tratamento. Copie o comando completo para esta prática.
urlopen abre a requisição, e with fecha a resposta ao sair do bloco. O programa exige status 200 e lê no máximo 1.000.001 bytes para verificar se ultrapassou o limite de 1.000.000. Em seguida, decodifica UTF-8 e interpreta o JSON. A documentação de urllib.request.urlopen explica esses argumentos e a resposta.
A estrutura aceita é uma lista de dicionários. Cada amount precisa ser um inteiro não negativo; type(... ) is int rejeita também valores booleanos, que não devem representar despesas. Campos como id e name aparecem na amostra, mas este cliente ainda não os valida nem verifica duplicatas. Ele valida somente o necessário para esta soma; um sistema de armazenamento exige um contrato mais completo.
Distinguir falhas HTTP, conexão e dados
HTTPError indica uma resposta HTTP de erro, como o status 404 de um caminho inexistente. URLError pode representar uma falha de conexão ou resolução de nome. Mesmo após uma resposta 200, podem ocorrer falhas de tamanho, decodificação, JSON ou validação dos registros. Veja as exceções de urllib.error.
O cliente encerra com uma mensagem em inglês que identifica o tipo de erro: por exemplo, request failed: HTTPError ou invalid record. Não substitui uma falha por uma lista vazia que pareceria uma consulta bem-sucedida. O exemplo trata as exceções listadas; não pretende capturar todos os problemas possíveis, como uma resposta HTTP malformada ou certas interrupções durante a leitura.
timeout=5 limita esperas de operações de rede; não estabelece um prazo absoluto de cinco segundos para todas as etapas somadas. Antes de adicionar novas tentativas, defina quantidade, intervalo e quais falhas podem ser repetidas. Requisições com efeitos, como criação de pagamentos, precisam de uma política de idempotência para evitar executar o mesmo efeito novamente.
- Troque apenas o nome solicitado por
missing.json. O servidor deve responder com erro HTTP, e o cliente deve encerrar sem imprimir totais de sucesso. - Restaure a URL. No JSON, transforme o primeiro
amountem string, usando"3500". A comunicação funciona, mas o cliente respondeinvalid record. Restaure o número e confirme os dois registros e o total original. - Encerre o servidor com Ctrl+C no primeiro terminal. Repita o cliente para observar uma falha de conexão, diferente de uma resposta válida.
Ao terminar, mantenha o servidor encerrado. Para uma API autenticada, gerencie tokens conforme a política do serviço e evite colocá-los diretamente no código, na URL ou em logs. Separe o diagnóstico da falha dos dados sensíveis presentes em uma requisição.




