Carreira: portfólio, GitHub, open source e o mercado Python

Carreira: portfólio, GitHub, open source e o mercado Python

O último artigo da série de Python: portfólio, README, contribuição open source, entrevistas e o mercado — com o código das perguntas clássicas conferido, o palíndromo que falha com acento, e certificações que foram encerradas antes de você estudar para elas.
Python

• • 18 min de leitura

Você chegou ao último artigo da série de Python. Ao longo de 52 artigos e 9 módulos, percorremos Python do zero até sistemas de produção completos. Agora vem a pergunta que realmente importa: como transformar esse conhecimento em carreira? Neste artigo final abordamos construção de portfólio, presença no GitHub, contribuição open source, preparação para entrevistas e o panorama atual do mercado Python no Brasil e no mundo.

O Mercado Python

Python lidera o índice TIOBE, que mede a popularidade das linguagens — em setembro de 2026, estava em primeiro lugar, com 17,8% —, e aparece entre as mais usadas em pesquisas como a Stack Overflow Developer Survey e o GitHub Octoverse. No Brasil, a demanda cresceu nos últimos anos, especialmente em:

Áreas com maior demanda:

Área                    Senioridade mais buscada    Faixa salarial (BR, ref. 2024)
─────────────────────────────────────────────────────────────────────────────
Backend / APIs          Pleno e Sênior              R$ 8k – R$ 20k
Data Science / ML       Pleno e Sênior              R$ 10k – R$ 25k
DevOps / MLOps          Sênior                      R$ 15k – R$ 30k
Automação / RPA         Júnior a Pleno              R$ 5k – R$ 12k
Data Engineering        Pleno e Sênior              R$ 12k – R$ 28k
Fullstack (Django/Fast) Pleno                       R$ 8k – R$ 18k

As faixas salariais são estimativas de referência de 2024, sem uma pesquisa específica por trás, e variam muito por região, empresa e regime de contratação. Antes de uma negociação, consulte levantamentos atuais de salários da área e vagas reais do seu nível.

Stacks mais cobradas nas vagas:

stacks_mais_pedidas = {
    "backend":      ["FastAPI", "Django", "Flask", "PostgreSQL", "Redis", "Docker"],
    "data_science": ["pandas", "scikit-learn", "TensorFlow", "MLflow", "Airflow"],
    "devops":       ["Docker", "Kubernetes", "GitHub Actions", "Terraform", "AWS"],
    "dados":        ["Spark", "dbt", "Airflow", "BigQuery", "Snowflake"],
}

Construindo seu Portfólio

Um portfólio não é uma lista de projetos — é uma narrativa sobre quem você é como desenvolvedor. Cada projeto deve demonstrar uma competência específica.

Estrutura Ideal do Portfólio

Portfólio
├── Projeto Âncora (1)      ← demonstra sua área principal
├── Projetos de Destaque (2-3) ← mostram amplitude
├── Contribuições Open Source ← mostra colaboração
└── Artigos / Blog Posts     ← demonstra comunicação técnica

O que torna um projeto de portfólio forte

criterios_projeto_forte = {
    "problema_real":       "Resolve algo que pessoas realmente usariam",
    "codigo_limpo":        "Bem organizado, tipado, testado e documentado",
    "readme_excelente":    "Explica o que é, como instalar e como usar",
    "demonstracao_viva":   "Deploy funcionando — não apenas código no GitHub",
    "decisoes_explicadas": "Documenta por que escolheu certas tecnologias",
    "testes":              "Cobertura mínima de 70%",
    "ci_cd":               "GitHub Actions rodando a cada push",
}

GitHub como Cartão de Visita

Seu perfil GitHub é a primeira coisa que recrutadores técnicos verificam. Invista nele como um profissional.

README de Perfil

Crie o arquivo username/username/README.md para customizar seu perfil:

# Olá, sou Ricardo Matos 👋

Desenvolvedor Python com foco em APIs e Data Science.
Apaixonado por código limpo, testes e arquitetura bem pensada.

## 🛠️ Stack Principal

![Python](https://img.shields.io/badge/Python-3776AB?style=flat&logo=python&logoColor=white)
![FastAPI](https://img.shields.io/badge/FastAPI-009688?style=flat&logo=fastapi&logoColor=white)
![PostgreSQL](https://img.shields.io/badge/PostgreSQL-316192?style=flat&logo=postgresql&logoColor=white)
![Docker](https://img.shields.io/badge/Docker-2496ED?style=flat&logo=docker&logoColor=white)

## 📌 Projetos em Destaque

| Projeto | Descrição | Stack |
|---------|-----------|-------|
| [escola-api](link) | API REST completa para gestão escolar | FastAPI, PostgreSQL, Docker |
| [evasao-predictor](link) | Modelo ML para predição de evasão | scikit-learn, MLflow, FastAPI |
| [job-bot](link) | Bot de monitoramento de vagas | BeautifulSoup, Telegram, asyncio |

## 📊 Estatísticas

![Stats](https://github-readme-stats.vercel.app/api?username=seuusuario&show_icons=true&theme=default)

## 📫 Contato

[![LinkedIn](https://img.shields.io/badge/LinkedIn-0077B5?style=flat&logo=linkedin)](link)
[![Email](https://img.shields.io/badge/Email-D14836?style=flat&logo=gmail)](mailto:email)

README de Projeto

# Escola API 🎓

API REST para gestão escolar construída com FastAPI e PostgreSQL.

[![CI](https://github.com/usuario/escola-api/actions/workflows/ci.yml/badge.svg)](link)
[![Coverage](https://codecov.io/gh/usuario/escola-api/badge.svg)](link)
[![Python](https://img.shields.io/badge/python-3.12-blue)](link)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](link)

## 🚀 Demo

> API ao vivo: https://escola-api.onrender.com/docs

## ✨ Funcionalidades

- ✅ CRUD completo de alunos, turmas e disciplinas
- ✅ Autenticação JWT com refresh tokens
- ✅ Paginação, filtros e busca em todos os endpoints
- ✅ Documentação interativa via Swagger UI
- ✅ Cobertura de testes > 90%
- ✅ Deploy automatizado via GitHub Actions

## 🛠️ Tecnologias

- **Python 3.12** + **FastAPI** — framework web assíncrono
- **PostgreSQL** + **SQLAlchemy** — banco e ORM
- **Alembic** — migrações de banco
- **pytest** + **pytest-cov** — testes
- **Docker** + **Docker Compose** — containerização
- **GitHub Actions** — CI/CD

## ⚡ Início Rápido

```bash
git clone https://github.com/usuario/escola-api
cd escola-api
cp .env.example .env
docker compose up -d
# API em: http://localhost:8000/docs
```

## 🏗️ Arquitetura

```
app/
├── routers/      ← endpoints REST
├── services/     ← lógica de negócio
├── repositories/ ← acesso ao banco
├── schemas/      ← validação Pydantic
└── models/       ← modelos ORM
```

## 🧭 Decisões Técnicas

- **FastAPI** em vez de Flask: validação com Pydantic e documentação automática
- **Repository Pattern**: desacopla a lógica de negócio do banco de dados
- **Soft delete**: alunos são desativados, não removidos — preserva o histórico

## 📄 Licença

MIT — veja [LICENSE](LICENSE)

A seção "Decisões Técnicas" é a que mais pesa numa avaliação: ela mostra que as escolhas foram feitas de propósito, e não copiadas de um tutorial. Vale também ser honesto na lista de funcionalidades — um recrutador técnico abre o código, e "cobertura de testes > 90%" precisa ser verdade no relatório do CI.

Contribuindo com Open Source

Contribuir com projetos open source é uma das formas mais eficazes de demonstrar habilidade real — e de aprender com desenvolvedores experientes.

Como começar

passos_para_contribuir = [
    "1. Use projetos open source — identifique problemas reais",
    "2. Leia CONTRIBUTING.md — cada projeto tem suas regras",
    "3. Comece pequeno — typos, docs, testes são bem-vindos",
    "4. Reproduza bugs — confirme o problema antes de abrir PR",
    "5. Abra uma issue primeiro — valide antes de implementar",
    "6. Fork → branch → commits atômicos → PR com descrição clara",
    "7. Responda feedback com paciência e profissionalismo",
]

Projetos Python que aceitam bem contribuições

projetos_para_contribuir = {
    "iniciante": [
        "first-contributions/first-contributions",
        "python/cpython (docs e testes)",
        "pypa/pip (issues com 'good first issue')",
    ],
    "intermediario": [
        "fastapi/fastapi",
        "pydantic/pydantic",
        "pallets/flask",
        "encode/httpx",
    ],
    "avancado": [
        "pandas-dev/pandas",
        "scikit-learn/scikit-learn",
        "astral-sh/ruff",
        "python/mypy",
    ]
}

Fluxo de contribuição

# 1. Fork no GitHub → clone local
git clone https://github.com/SEU_USUARIO/fastapi.git
cd fastapi

# 2. Configurar upstream
git remote add upstream https://github.com/fastapi/fastapi.git   # o repositório saiu de tiangolo/ em 2024

# 3. Uma branch por contribuição, com nome descritivo
git checkout -b fix/typo-in-readme
# outros exemplos de nome: feat/add-example-to-docs, fix/issue-123-validation-error

# 4. Commits atômicos e descritivos
git commit -m "fix: corrige typo em tutorial de security"
git commit -m "docs: adiciona exemplo de uso do Depends"
git commit -m "test: adiciona teste para edge case de query param"

# 5. Sincronizar antes de abrir PR
git fetch upstream
git rebase upstream/main

# 6. Push e Pull Request
git push origin fix/typo-in-readme
# Abrir PR no GitHub com descrição clara

Preparação para Entrevistas

Tipos de entrevista Python

formatos_entrevista = {
    "triagem_tecnica": {
        "formato":   "Quiz ou desafio online (30-60 min)",
        "conteudo":  ["sintaxe", "estruturas de dados", "OOP", "algoritmos simples"],
        "plataformas": ["HackerRank", "LeetCode", "Codility"],
    },
    "pair_programming": {
        "formato":  "Codificação ao vivo com o entrevistador (60-90 min)",
        "conteudo": ["resolver problema real", "comunicar raciocínio", "refatorar"],
        "dica":     "Pense em voz alta — o processo importa tanto quanto a solução",
    },
    "revisao_codigo": {
        "formato":  "Revisar código enviado por você ou pelo entrevistador",
        "conteudo": ["detectar bugs", "sugerir melhorias", "discutir trade-offs"],
    },
    "system_design": {
        "formato":  "Projetar um sistema em alto nível (45-60 min)",
        "conteudo": ["escalabilidade", "banco de dados", "cache", "filas"],
        "exemplos": ["Projetar uma API de encurtador de URLs",
                     "Projetar sistema de notificações"],
    },
}

Questões técnicas comuns

# Questão 1: GIL e concorrência
# "Quando usar threading vs multiprocessing?"
resposta_threading = """
Threading é adequado para I/O intensivo (rede, disco) — o GIL é liberado
durante operações de I/O, permitindo concorrência real.
Multiprocessing é necessário para CPU intensivo — cada processo tem seu
próprio interpretador, sem GIL.
asyncio é a melhor escolha para I/O massivo com alta concorrência.
Desde o Python 3.13 existe um build sem GIL, e na 3.14 o free-threading
é oficialmente suportado (ainda não é o padrão): threads passam a
rodar código Python em paralelo de verdade nesse build.
"""

# Questão 2: Mutabilidade e efeitos colaterais
def bug_classico(lista=[]):    # ✗ argumento mutável padrão
    lista.append(1)
    return lista

# Chamadas subsequentes compartilham o mesmo objeto
bug_classico()   # [1]
bug_classico()   # [1, 1] — surpresa!

def correto(lista=None):       # ✓
    if lista is None:
        lista = []
    lista.append(1)
    return lista


# Questão 3: Decoradores
# "Implemente um decorador de cache simples"
from functools import wraps

# (na biblioteca padrão: @functools.cache faz o mesmo, com mais cuidado)
def cache_simples(func):
    _cache = {}
    @wraps(func)
    def wrapper(*args):
        if args not in _cache:
            _cache[args] = func(*args)
        return _cache[args]
    return wrapper

@cache_simples
def fibonacci(n):
    if n <= 1: return n
    return fibonacci(n-1) + fibonacci(n-2)


# Questão 4: Generators
# "Qual a diferença entre list comprehension e generator expression?"
lista  = [x**2 for x in range(1000000)]    # carrega tudo na memória
gen    = (x**2 for x in range(1000000))    # gera sob demanda — O(1) memória

# Questão 5: Context managers
# "Implemente um context manager"
from contextlib import contextmanager

@contextmanager
def temporizador(nome):
    import time
    inicio = time.perf_counter()
    try:
        yield
    finally:
        duracao = time.perf_counter() - inicio
        print(f"{nome}: {duracao*1000:.2f}ms")

with temporizador("operacao"):
    resultado = sum(range(1_000_000))

Algoritmos mais cobrados

# LeetCode mais comuns em vagas Python

# 1. Two Sum — O(n) com hash map
def two_sum(nums, target):
    visto = {}
    for i, n in enumerate(nums):
        complemento = target - n
        if complemento in visto:
            return [visto[complemento], i]
        visto[n] = i
    return []


# 2. Palindrome — O(n)
def eh_palindromo(s):
    s = "".join(c.lower() for c in s if c.isalnum())
    return s == s[::-1]


# 3. Anagrama — O(n)
from collections import Counter
def eh_anagrama(s, t):
    return Counter(s) == Counter(t)


# 4. Binary Search — O(log n)
def busca_binaria(arr, alvo):
    esq, dir = 0, len(arr) - 1
    while esq <= dir:
        meio = (esq + dir) // 2
        if arr[meio] == alvo:   return meio
        elif arr[meio] < alvo:  esq = meio + 1
        else:                   dir = meio - 1
    return -1


# 5. FizzBuzz — clássico de triagem
def fizzbuzz(n):
    return [
        "FizzBuzz" if i % 15 == 0
        else "Fizz"    if i % 3  == 0
        else "Buzz"    if i % 5  == 0
        else str(i)
        for i in range(1, n + 1)
    ]

Plano de Desenvolvimento Contínuo

plano_pos_curso = {
    "imediato": [
        "Finalizar e publicar os 4 projetos da série no GitHub",
        "Criar README profissional para cada projeto",
        "Fazer deploy de pelo menos 1 projeto (Render, Railway, Fly.io)",
        "Montar LinkedIn com os projetos",
    ],
    "primeiro_mes": [
        "Resolver 30 problemas no LeetCode (Easy e Medium)",
        "Fazer 1 contribuição open source (doc ou teste)",
        "Publicar 1 artigo técnico (dev.to, Medium, blog próprio)",
        "Participar de 1 comunidade Python (Discord, fórum)",
    ],
    "tres_meses": [
        "Especializar em uma área (backend, data, devops)",
        "Completar 1 certificação (AWS, GCP, Databricks, etc.)",
        "Contribuir regularmente com 1 projeto open source",
        "Fazer 5 entrevistas técnicas — mesmo sem intenção de mudar",
    ],
    "seis_meses": [
        "Projeto pessoal com usuários reais",
        "Mentoria — ensinar alguém acelera o aprendizado",
        "Palestrar em meetup local (mesmo que pequeno)",
        "Revisar e atualizar portfólio continuamente",
    ],
}

Recursos para Continuar Aprendendo

recursos_essenciais = {
    "documentacao": [
        "https://docs.python.org/3/",
        "https://fastapi.tiangolo.com/",
        "https://pandas.pydata.org/docs/",
        "https://scikit-learn.org/stable/",
    ],
    "livros": [
        "Fluent Python — Luciano Ramalho (O'Reilly)",
        "Python Cookbook — Beazley & Jones (O'Reilly)",
        "Architecture Patterns with Python — Percival & Gregory",
        "Hands-On ML — Aurélien Géron (O'Reilly)",
        "Designing ML Systems — Chip Huyen (O'Reilly)",
    ],
    "pratica": [
        "https://leetcode.com/",
        "https://exercism.org/tracks/python",
        "https://www.kaggle.com/",
        "https://adventofcode.com/",
    ],
    "comunidade_br": [
        "Python Brasil — https://python.org.br/",
        "PyData Brasil",
        "Discord Python Brasil",
        "Grupy-SP, Grupy-RJ e outros grupos regionais",
    ],
    "newsletters": [
        "Python Weekly — https://www.pythonweekly.com/",
        "Real Python — https://realpython.com/",
        "PyCoder's Weekly — https://pycoders.com/",
    ],
}

Certificações Relevantes

certificacoes_valorosas = {
    "cloud": [
        "AWS Certified Developer – Associate",
        "Google Cloud Professional Data Engineer",
        "Azure Data Scientist Associate",
    ],
    "dados": [
        "Databricks Certified Associate Developer for Apache Spark",
        "dbt Certified Developer",
        "Snowflake SnowPro Core",
    ],
    "ml_ia": [
        # O exame TensorFlow Developer Certificate foi encerrado pelo Google,
        # e a AWS está aposentando a Machine Learning – Specialty
        # (conferido em setembro de 2026) — confira o status antes de estudar
        "DeepLearning.AI certifications (Coursera)",
    ],
    "python": [
        "PCEP — Python Certified Entry-Level Programmer (Python Institute)",
        "PCAP — Python Certified Associate Programmer",
        "PCPP — Python Certified Professional Programmer",
    ],
}

Mensagem Final

Você concluiu 52 artigos cobrindo Python de ponta a ponta — dos fundamentos às redes neurais, das APIs REST ao deploy em produção. Isso representa um corpo de conhecimento que a maioria dos desenvolvedores leva anos para acumular.

Mas o conhecimento técnico é apenas metade da equação. A outra metade é o que você faz com ele.

Algumas verdades que aprendi ao longo dos anos:

verdades_da_carreira = {
    "sobre_aprender": (
        "Você nunca vai saber tudo — e tudo bem. "
        "O objetivo é saber o suficiente para aprender o que falta."
    ),
    "sobre_projetos": (
        "Um projeto mediano publicado vale mais do que "
        "dez projetos perfeitos que nunca saíram do localhost."
    ),
    "sobre_comunidade": (
        "As melhores oportunidades vêm de conexões genuínas, "
        "não de currículos enviados para formulários."
    ),
    "sobre_senioridade": (
        "Senior não é quem sabe mais — é quem sabe o que não sabe "
        "e tem humildade para aprender."
    ),
    "sobre_bugs": (
        "Todo código tem bugs. Código sem testes tem bugs "
        "que você ainda não encontrou."
    ),
    "sobre_perfeicao": (
        "Feito é melhor que perfeito. "
        "Mas feito com testes é melhor que feito sem."
    ),
}

print("Obrigado por chegar até aqui.")
print("Agora vá construir algo real.")

Fontes e leituras recomendadas

Exercícios

Exercício 1

Numa entrevista, pedem para você explicar o que acontece com def bug_classico(lista=[]): lista.append(1); return lista depois de duas chamadas sem argumento. Você responde que a segunda devolve [1, 1]. O entrevistador pergunta: "E onde essa lista mora?". O que ele quer ouvir?

Ver resposta

✓ Resposta: Que ela mora na própria função. O valor padrão é avaliado uma única vez, quando o def é executado, e fica guardado em bug_classico.__defaults__. Toda chamada sem argumento recebe o mesmo objeto. Medido: depois de duas chamadas, bug_classico.__defaults__ vale ([1, 1],), e a lista acumulada está ali, visível. A pergunta testa se você entende que nomes em Python são rótulos para objetos, e não caixas que guardam valores: o padrão não é "uma lista vazia nova a cada chamada", é uma referência a uma lista criada uma vez. A correção, com None como sentinela e a lista criada dentro da função, você já sabe; o que diferencia a resposta é mostrar o mecanismo. O Ruff acusa o padrão com a regra B006, e vale dizer isso na entrevista: mostra que você conhece as ferramentas que evitam o erro.

Exercício 2

O eh_palindromo do artigo remove pontuação e espaços e compara a string com o inverso. Testado com "Socorram-me, subi no ônibus em Marrocos", um palíndromo famoso em português, ele devolve False. Por quê, e como corrigir sem montar uma tabela de acentos à mão?

Ver resposta

✓ Resposta: Por causa do "ô". Depois da limpeza, a frase vira "socorrammesubinoônibusemmarrocos", e na posição espelhada do "ô" está um "o" sem acento: para o Python, são caracteres diferentes. A saída é a normalização Unicode: unicodedata.normalize("NFD", s) decompõe cada letra acentuada em letra-base mais um acento combinante — "ô" vira "o" seguido de U+0302. O acento combinante é da categoria Mn, e "̂".isalnum() é False, então o filtro que já existe o descarta. Medido: com essa linha antes da limpeza, "Socorram-me, subi no ônibus em Marrocos", "Anotaram a data da maratona" e "A base do teto desaba" dão True. Numa entrevista no Brasil, perguntar "e se a frase tiver acento?" antes de codar é um ponto a favor: mostra que você pensa nos dados reais, e não só no exemplo do enunciado.

Exercício 3

Na questão sobre generators, o artigo diz que a lista "carrega tudo na memória" e o generator gera "sob demanda". Um entrevistador pede números: quanto ocupam [x**2 for x in range(1000000)] e (x**2 for x in range(1000000))? E quando o generator não é a escolha certa?

Ver resposta

✓ Resposta: Medido com sys.getsizeof no Python 3.14: a lista ocupa 8.448.728 bytes, e o generator, 208. E a medida da lista é só a do vetor de referências — os um milhão de inteiros apontados por ela ocupam ainda mais memória, fora dessa conta. O generator guarda apenas o estado da iteração, e cada valor é calculado quando pedido. Ele não é a escolha certa quando os dados precisam ser percorridos mais de uma vez, porque um generator se esgota na primeira passada, e a segunda devolve nada, sem erro; quando é preciso acesso por índice ou len(); e quando a coleção é pequena e será toda usada, caso em que a lista costuma ser mais rápida. A resposta completa, numa entrevista, é essa troca: memória constante e cálculo sob demanda contra uma única passada e nenhum acesso aleatório.

Exercício 4

O decorador cache_simples da questão 3 funciona bem com fibonacci. Um colega o aplica a uma função que recebe uma lista de notas e recebe TypeError: cannot use 'tuple' as a dict key (unhashable type: 'list'). Explique o erro e diga o que a biblioteca padrão oferece.

Ver resposta

✓ Resposta: O cache usa a tupla de argumentos como chave de dicionário, e uma tupla só é hasheável se todos os elementos forem. Uma lista não é, porque é mutável: se ela mudasse depois de virar chave, o dicionário a guardaria no lugar errado. Medido: a chamada com [1, 2] falha exatamente com essa mensagem. A versão do artigo tem ainda outras limitações: ignora argumentos nomeados, cresce sem limite e não tem como ser limpa. A biblioteca padrão resolve isso com @functools.cache, que é ilimitado, e @functools.lru_cache(maxsize=128), que descarta os itens menos usados; os dois aceitam argumentos nomeados e oferecem cache_info() e cache_clear(). Para argumentos mutáveis, a saída é converter antes, por exemplo tuple(notas). Numa entrevista, implementar o cache e depois citar o functools mostra as duas coisas que se espera: entender o mecanismo e não reinventá-lo em produção.

Exercício 5

Seguindo uma lista de certificações de dois anos atrás, uma pessoa planeja estudar para o "TensorFlow Developer Certificate" e a "AWS Certified Machine Learning – Specialty". Consultados em setembro de 2026, os sites oficiais dizem: "we have closed the TensorFlow Certificate exam" e "This certification is being retired". Que lição de carreira isso ensina, além de trocar os nomes da lista?

Ver resposta

✓ Resposta: Que qualquer lista de recursos de carreira envelhece, e rápido — esta aqui inclusive. Certificações são produtos das empresas que as emitem e são criadas, reformuladas e aposentadas conforme a estratégia delas; uma que valia muito há dois anos pode nem existir hoje. Antes de investir semanas de estudo e o valor da prova, confira a página oficial da certificação, a data de aposentadoria, se houver, e o que a substitui. Nos dois casos citados, a própria página informa o status. A lição mais ampla vale para tudo no artigo: o repositório do FastAPI mudou de tiangolo/fastapi para fastapi/fastapi em 2024, e o endereço antigo só funciona por redirecionamento; as faixas salariais são de 2024; os rankings de linguagem mudam todo mês. Um profissional sênior não é o que sabe a lista de cor, e sim o que confere a fonte antes de agir.

Comentários

Mais em Python

Automação de Planilhas e PDFs
Automação de Planilhas e PDFs

Planilhas e PDFs com Python: boletim estilizado com gráfico no openpyxl…

MLOps: Versionamento de Modelos, MLflow e Deploy de ML
MLOps: Versionamento de Modelos, MLflow e Deploy de ML

MLflow 3 na prática: experimentos, registro de modelos com aliases, API com…

Consumindo APIs REST com requests e httpx
Consumindo APIs REST com requests e httpx

Consumindo APIs REST em Python com requests e httpx, do GET simples ao cliente…