Consumindo APIs REST com Python — 2025 | Python Brasil

Aprenda a consumir APIs REST com Python e requests. GET, POST, autenticação e paginação. Comece agora!

5 min de leitura Equipe Python Brasil

APIs REST (Representational State Transfer) são a principal forma de comunicação entre sistemas na web moderna. Desde consultar a previsão do tempo até integrar sistemas de pagamento, consumir APIs é uma habilidade essencial para qualquer desenvolvedor Python. A biblioteca requests torna esse trabalho simples e intuitivo.

Neste artigo, vamos aprender a fazer requisições HTTP, trabalhar com autenticação, tratar erros de rede e construir integrações robustas com APIs externas.

Instalação e primeira requisição

A biblioteca requests é o padrão da comunidade Python para requisições HTTP:

# No terminal:
# pip install requests

import requests

# Requisição GET simples
resposta = requests.get("https://api.github.com")
print(f"Status: {resposta.status_code}")
print(f"Headers: {resposta.headers['content-type']}")
print(f"Dados: {resposta.json()}")

O objeto Response contém todas as informações da resposta: status code, headers, corpo e cookies. O método .json() converte automaticamente o corpo da resposta em um dicionário Python.

Métodos HTTP: GET, POST, PUT, DELETE

Cada método HTTP tem um propósito específico na interação com APIs:

import requests

BASE_URL = "https://jsonplaceholder.typicode.com"

# GET - Buscar dados
resposta = requests.get(f"{BASE_URL}/posts/1")
post = resposta.json()
print(f"Título: {post['title']}")

# GET com parâmetros de query
params = {"userId": 1, "_limit": 3}
resposta = requests.get(f"{BASE_URL}/posts", params=params)
posts = resposta.json()
print(f"\nPosts do usuário 1 (limite 3):")
for p in posts:
    print(f"  - {p['title'][:50]}...")

# POST - Criar dados
novo_post = {
    "title": "Meu post via Python",
    "body": "Conteúdo criado automaticamente com requests.",
    "userId": 1
}
resposta = requests.post(f"{BASE_URL}/posts", json=novo_post)
print(f"\nPost criado - ID: {resposta.json()['id']}")
print(f"Status: {resposta.status_code}")

# PUT - Atualizar dados (substituição completa)
post_atualizado = {
    "id": 1,
    "title": "Título atualizado",
    "body": "Corpo atualizado via Python.",
    "userId": 1
}
resposta = requests.put(f"{BASE_URL}/posts/1", json=post_atualizado)
print(f"\nPost atualizado: {resposta.json()['title']}")

# PATCH - Atualização parcial
resposta = requests.patch(
    f"{BASE_URL}/posts/1",
    json={"title": "Apenas o título mudou"}
)
print(f"Título alterado: {resposta.json()['title']}")

# DELETE - Remover dados
resposta = requests.delete(f"{BASE_URL}/posts/1")
print(f"\nPost removido - Status: {resposta.status_code}")

A diferença entre json= e data= é importante: json= serializa automaticamente o dicionário para JSON e define o Content-Type correto, enquanto data= envia os dados como formulário.

Tratamento de erros e timeout

Requisições de rede podem falhar por diversos motivos. Um código robusto precisa tratar essas situações:

import requests
from requests.exceptions import (
    ConnectionError, Timeout, HTTPError, RequestException
)

def fazer_requisicao(url, timeout=10):
    """Faz uma requisição GET com tratamento completo de erros."""
    try:
        resposta = requests.get(url, timeout=timeout)
        resposta.raise_for_status()  # Levanta exceção para status 4xx e 5xx
        return resposta.json()

    except ConnectionError:
        print(f"Erro de conexão: não foi possível acessar {url}")
        return None
    except Timeout:
        print(f"Timeout: o servidor não respondeu em {timeout} segundos")
        return None
    except HTTPError as e:
        print(f"Erro HTTP {e.response.status_code}: {e.response.reason}")
        return None
    except RequestException as e:
        print(f"Erro inesperado na requisição: {e}")
        return None

# Testando
dados = fazer_requisicao("https://api.github.com/users/python")
if dados:
    print(f"Usuário: {dados['login']}")
    print(f"Repositórios públicos: {dados['public_repos']}")

O raise_for_status() é uma ferramenta valiosa: ele converte códigos de status HTTP 400-599 em exceções Python, permitindo que você os trate com try/except.

Autenticação

APIs protegidas exigem autenticação. Os métodos mais comuns são token Bearer e API keys:

import requests

# Autenticação com token Bearer (OAuth2)
token = "seu_token_aqui"
headers = {
    "Authorization": f"Bearer {token}",
    "Accept": "application/json"
}
resposta = requests.get(
    "https://api.github.com/user",
    headers=headers
)

# Autenticação com API key via header
headers = {"X-API-Key": "sua_chave_aqui"}
resposta = requests.get(
    "https://api.exemplo.com/dados",
    headers=headers
)

# Autenticação com API key via query parameter
params = {"api_key": "sua_chave_aqui", "cidade": "São Paulo"}
resposta = requests.get(
    "https://api.exemplo.com/clima",
    params=params
)

# Autenticação básica (usuário e senha)
resposta = requests.get(
    "https://api.exemplo.com/admin",
    auth=("usuario", "senha")
)

Sessões para múltiplas requisições

Quando você faz várias requisições para a mesma API, usar uma sessão é mais eficiente:

import requests

class ClienteAPI:
    """Cliente para consumir uma API REST."""

    def __init__(self, base_url, token):
        self.base_url = base_url
        self.sessao = requests.Session()
        self.sessao.headers.update({
            "Authorization": f"Bearer {token}",
            "Accept": "application/json",
            "Content-Type": "application/json"
        })
        self.sessao.timeout = 15

    def get(self, endpoint, params=None):
        """Faz uma requisição GET."""
        url = f"{self.base_url}/{endpoint}"
        resposta = self.sessao.get(url, params=params)
        resposta.raise_for_status()
        return resposta.json()

    def post(self, endpoint, dados):
        """Faz uma requisição POST."""
        url = f"{self.base_url}/{endpoint}"
        resposta = self.sessao.post(url, json=dados)
        resposta.raise_for_status()
        return resposta.json()

    def fechar(self):
        """Fecha a sessão."""
        self.sessao.close()

# Uso:
# cliente = ClienteAPI("https://api.exemplo.com/v1", "meu_token")
# usuarios = cliente.get("usuarios", params={"page": 1})
# novo = cliente.post("usuarios", {"nome": "Ana", "email": "ana@email.com"})
# cliente.fechar()

Sessões reutilizam conexões TCP e mantêm cookies e headers entre requisições, o que melhora significativamente a performance.

Trabalhando com paginação

Muitas APIs retornam dados paginados. Veja como consumir todas as páginas:

import requests

def buscar_todos_repositorios(usuario):
    """Busca todos os repositórios de um usuário do GitHub."""
    repositorios = []
    pagina = 1
    por_pagina = 100

    while True:
        resposta = requests.get(
            f"https://api.github.com/users/{usuario}/repos",
            params={"page": pagina, "per_page": por_pagina, "sort": "updated"},
            timeout=10
        )
        resposta.raise_for_status()
        dados = resposta.json()

        if not dados:
            break

        repositorios.extend(dados)
        pagina += 1

        if len(dados) < por_pagina:
            break

    return repositorios

# Uso:
# repos = buscar_todos_repositorios("python")
# print(f"Total de repositórios: {len(repos)}")
# for repo in repos[:5]:
#     print(f"  {repo['name']} - {repo['stargazers_count']} estrelas")

Boas práticas ao consumir APIs

Para integrações robustas e profissionais:

  • Sempre defina timeout: requisições sem timeout podem travar seu programa indefinidamente.
  • Use raise_for_status(): trate erros HTTP explicitamente em vez de verificar status codes manualmente.
  • Armazene credenciais de forma segura: use variáveis de ambiente, nunca hardcode tokens no código.
  • Respeite rate limits: verifique os headers X-RateLimit-* e implemente backoff quando necessário.
  • Use sessões: para múltiplas requisições ao mesmo servidor, sessões são mais eficientes.
  • Faça cache quando possível: evite requisições desnecessárias armazenando respostas em cache.
  • Documente as integrações: mantenha documentação sobre quais APIs são consumidas, endpoints usados e formatos esperados.

Conclusão

Consumir APIs REST com Python e requests é uma habilidade fundamental no desenvolvimento moderno. Praticamente todo sistema precisa se integrar com serviços externos, e a biblioteca requests torna esse processo simples e produtivo. Com tratamento adequado de erros, autenticação e boas práticas, suas integrações serão confiáveis e fáceis de manter.

Como próximos passos, explore a biblioteca httpx para requisições assíncronas, aprenda sobre GraphQL como alternativa ao REST e estude como criar suas próprias APIs com FastAPI ou Django REST Framework.

E

Equipe Python Brasil

Contribuidor do Python Brasil — Aprenda Python em Português