Capítulo 19: FastAPI com Banco de Dados (SQLite) 🦅🏛️

Neste capítulo, vamos juntar o FastAPI com o SQLite (que aprendemos no Capítulo 14) para criar uma API que busca dados reais em um banco de dados, com o tema Assassin’s Creed!


📖 Por que conectar a API ao Banco de Dados?

Até agora, nossas respostas do FastAPI eram fixas no código (hardcoded). Conectando a um banco de dados, podemos criar aplicações dinâmicas reais, onde os dados podem ser cadastrados, alterados e consultados via web!


📖 Exemplo Guiado: Registro do Animus

Vamos criar um banco de dados de assassinos e uma rota no FastAPI que busca um assassino pelo ID.

  1. Crie o arquivo criar_banco.py na pasta src/ para preparar os dados:
import sqlite3
 
def init_db():
    conn = sqlite3.connect('animus.db')
    cursor = conn.cursor()
    
    cursor.execute('''
    CREATE TABLE IF NOT EXISTS assassinos (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        nome TEXT,
        epoca TEXT
    )
    ''')
    
    # Inserindo alguns dados de exemplo
    cursor.execute("SELECT COUNT(*) FROM assassinos")
    if cursor.fetchone()[0] == 0:
        cursor.execute("INSERT INTO assassinos (nome, epoca) VALUES ('Altaïr', 'Terceira Cruzada')")
        cursor.execute("INSERT INTO assassinos (nome, epoca) VALUES ('Ezio Auditore', 'Renascimento')")
        cursor.execute("INSERT INTO assassinos (nome, epoca) VALUES ('Eivor', 'Era Viking')")
        conn.commit()
    
    conn.close()
 
if __name__ == '__main__':
    init_db()
    print("Banco animus.db criado e populado!")
  1. Crie o arquivo app_animus.py na pasta src/:
from fastapi import FastAPI, HTTPException
import sqlite3
 
app = FastAPI()
 
def busca_no_banco(id_assassino: int):
    conn = sqlite3.connect('animus.db')
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM assassinos WHERE id = ?", (id_assassino,))
    resultado = cursor.fetchone()
    conn.close()
    return resultado
 
@app.get('/assassino/{id}')
def obter_assassino(id: int):
    dados = busca_no_banco(id)
    
    if dados:
        # O FastAPI converte dicionários para JSON automaticamente!
        return {
            "id": dados[0],
            "nome": dados[1],
            "epoca": dados[2]
        }
    else:
        # Forma correta de retornar erros no FastAPI
        raise HTTPException(status_code=404, detail="Registro não encontrado no Animus")

🕹️ Como Executar e Testar no VS Code

  1. Rode primeiro o criar_banco.py para criar o arquivo de banco de dados.
  2. No terminal, execute: uvicorn app_animus:app --reload
  3. Acesse no navegador: http://127.0.0.1:8000/assassino/2

Resultado Esperado no Navegador:

{
  "epoca": "Renascimento",
  "id": 2,
  "nome": "Ezio Auditore"
}

📊 Ilustração Visual: Fluxo FastAPI + DB

Veja o caminho que a informação faz:

graph LR
    A["🌐 Navegador"] -->|1. Pede ID 2| B["💻 API FastAPI"]
    B -->|2. Consulta SQL| C[(🗄️ SQLite: animus.db)]
    C -->|3. Retorna Linha| B
    B -->|4. Retorna JSON| A

🛠️ Prática Obrigatória 1: Listar Todos

Crie uma nova rota chamada /assassinos que busque todos os assassinos cadastrados no banco e os retorne em uma lista. (Dica: use cursor.execute("SELECT * FROM assassinos") e cursor.fetchall()). Lembre-se de retornar uma lista de dicionários!


🔑 Gabarito de Código

Prática 1: Nova rota no app_animus.py

@app.get('/assassinos')
def listar_todos():
    conn = sqlite3.connect('animus.db')
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM assassinos")
    resultados = cursor.fetchall()
    conn.close()
    
    lista = []
    for r in resultados:
        lista.append({"id": r[0], "nome": r[1], "epoca": r[2]})
        
    return lista

📤 Instruções de Entrega (GitHub Desktop + Microsoft Teams)

(Siga o mesmo padrão do Capítulo 01)


Capitulo Anterior | Proximo Capitulo