Construir uma API To-Do com FastAPI é uma excelente maneira de aprimorar suas habilidades de desenvolvimento backend e fortalecer seu portfólio. Este guia prático irá te mostrar como criar uma API completa, utilizando FastAPI, PostgreSQL e SQLAlchemy. Você aprenderá desde a configuração do banco de dados até a implementação das operações CRUD (Criar, Ler, Atualizar e Deletar), garantindo que sua API esteja pronta para produção.
Configuração Inicial do Projeto
Passo 1: Instalação das Dependências
Antes de mergulhar no código, é crucial instalar todas as bibliotecas necessárias para o nosso projeto. Utilize o pip, o gerenciador de pacotes do Python, para instalar o FastAPI, psycopg2 (para conectar ao PostgreSQL), Pydantic (para validação de dados), SQLAlchemy (para ORM), Uvicorn (servidor ASGI) e python-dotenv (para gerenciar variáveis de ambiente).
pip install fastapi psycopg2 pydantic SQLAlchemy uvicorn python-dotenv
Essas dependências são a espinha dorsal do nosso projeto, permitindo que o FastAPI interaja com o banco de dados PostgreSQL de forma eficiente e segura.
Passo 2: Estrutura do Projeto
A organização do seu projeto é fundamental para a manutenção e escalabilidade. A estrutura recomendada é a seguinte:
📂 todo_api_project
┣ 📜 main.py # Entry point of the application
┣ 📜 database.py # Database configuration
┣ 📜 model.py # Database models
┣ 📜 schema.py # Pydantic schemas
┣ 📜 route.py # API routes
┗ 📜 requirements.txt # Dependencies
Cada arquivo tem uma responsabilidade específica, facilitando a navegação e o entendimento do código. O arquivo main.py será o ponto de entrada da aplicação, enquanto os outros arquivos cuidarão da configuração do banco de dados, modelos, schemas e rotas da API.
Configurando o Banco de Dados
Passo 3: Configurando o PostgreSQL
Para configurar o banco de dados, vamos criar um arquivo chamado database.py. Este arquivo conterá o código necessário para conectar nossa API ao banco de dados PostgreSQL. Usaremos o SQLAlchemy para facilitar essa conexão.
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
DATABASE_URL = "postgresql://yourusername:yourpassword@localhost/todo_db"
engine = create_engine(DATABASE_URL)
sessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
BASE = declarative_base()
def get_db():
db = sessionLocal()
try:
yield db
finally:
db.close()
Certifique-se de substituir yourusername e yourpassword pelas suas credenciais do PostgreSQL. Este código cria uma conexão com o banco de dados, gerencia as sessões e define a base para os modelos do banco de dados.
Entendendo o Código
create_engine
: Usado para conectar ao banco de dados PostgreSQL.sessionLocal
: Gerencia as sessões do banco de dados.BASE = declarative_base()
: Permite definir os modelos do banco de dados.get_db
: Função que fornece uma sessão de banco de dados quando necessário.
Definindo os Modelos e Schemas
Passo 4: Criando o Modelo To-Do
No arquivo model.py, definiremos a estrutura dos nossos itens To-Do usando o SQLAlchemy. Este modelo representará a tabela no banco de dados que armazenará as informações das tarefas.
from sqlalchemy import Column, Integer, String, Boolean, TIMESTAMP, text
from database import BASE
class Todo(BASE):
__tablename__ = "todos"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, nullable=False)
description = Column(String, nullable=True)
published = Column(Boolean, server_default=text("False"))
created_at = Column(TIMESTAMP(timezone=True), server_default=text("now()"))
Cada coluna na classe Todo representa um campo na tabela todos do banco de dados. O id é a chave primária, title é o título da tarefa (obrigatório), description é uma descrição opcional, published indica se a tarefa está publicada (padrão é False), e created_at armazena o timestamp de criação.
Detalhes dos Campos
id
: Chave primária gerada automaticamente.title
: Campo obrigatório (nullable=False
).description
: Campo opcional (nullable=True
).published
: Campo booleano com valor padrão False.created_at
: Armazena o timestamp de criação.
Passo 5: Criando Schemas Pydantic
No arquivo schema.py, definiremos como o Pydantic validará os dados das requisições recebidas. Os schemas garantem que os dados estejam no formato correto antes de serem processados pela API. Veja os detalhes dos campos.
from typing import Optional
from pydantic import BaseModel
class Todo(BaseModel):
title: str
description: Optional[str] = None
published: bool = False
class Config:
orm_mode = True
class UpdateTodo(BaseModel):
title: Optional[str] = None
description: Optional[str] = None
published: Optional[bool] = None
O schema Todo é usado para criar novas tarefas, enquanto o schema UpdateTodo é usado para atualizar tarefas existentes. O orm_mode = True
garante a compatibilidade com os modelos SQLAlchemy.
Funções dos Schemas
Todo
: Usado para criar novas tarefas.UpdateTodo
: Usado para atualizar tarefas.orm_mode = True
: Garante compatibilidade com modelos SQLAlchemy.
Implementando as Rotas da API
Passo 6: Criando as Rotas da API
Agora, vamos criar os endpoints da API no arquivo route.py. Aqui, definiremos as operações CRUD para gerenciar as tarefas To-Do. Vamos usar o FastAPI para criar as rotas e interagir com o banco de dados.
from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session
from database import get_db, engine
from schema import Todo, UpdateTodo
import model
from typing import List
# Create tables
model.BASE.metadata.create_all(bind=engine)
route = APIRouter()
Este código inicializa o roteador FastAPI e cria as tabelas no banco de dados se elas ainda não existirem.
1️⃣ Obter Todas as Tarefas To-Do
@route.get("/getalltodos")
def get_all_todo(db: Session = Depends(get_db)):
todos = db.query(model.Todo).all()
return todos if todos else []
Esta rota busca todas as tarefas do banco de dados e retorna uma lista. Se não houver tarefas, retorna uma lista vazia.
2️⃣ Criar uma Nova Tarefa To-Do
@route.post("/todo/create")
def create_todo(todo: Todo, db: Session = Depends(get_db)):
todo_item = model.Todo(**todo.model_dump())
db.add(todo_item)
db.commit()
db.refresh(todo_item)
return todo_item
Esta rota recebe um JSON como entrada e adiciona uma nova tarefa ao banco de dados. Ela usa o schema Todo para validar os dados antes de criar a tarefa.
3️⃣ Atualizar uma Tarefa To-Do
@route.put("/todo/update/{post_id}", response_model=UpdateTodo)
def update_todo(new_post: UpdateTodo, post_id: int, db: Session = Depends(get_db)):
todo = db.query(model.Todo).filter(model.Todo.id == post_id).first()
if not todo:
return {"error": "To-do not found"}
update_data = new_post.model_dump(exclude_unset=True)
for key, value in update_data.items():
setattr(todo, key, value)
db.commit()
db.refresh(todo)
return todo
Esta rota atualiza uma tarefa existente com base no id fornecido. Ela usa o schema UpdateTodo para validar os dados antes de atualizar a tarefa.
4️⃣ Obter Tarefas To-Do Publicadas
@route.get("/published_todo")
def get_published_todos(db: Session = Depends(get_db)):
return db.query(model.Todo).filter(model.Todo.published == True).all()
Esta rota busca todas as tarefas que estão publicadas (published é True) no banco de dados.
5️⃣ Obter Tarefas To-Do em Rascunho
@route.get("/draft_todo")
def get_draft_post(db: Session = Depends(get_db)):
return db.query(model.Todo).filter(model.Todo.published == False).all()
Esta rota busca todas as tarefas que estão em rascunho (published é False) no banco de dados.
6️⃣ Obter uma Tarefa To-Do por ID
@route.get("/getbyid/{todo_id}")
def get_by_id(todo_id: int, db: Session = Depends(get_db)):
return db.query(model.Todo).filter(model.Todo.id == todo_id).first()
Esta rota busca uma tarefa específica pelo seu id.
7️⃣ Pesquisar Tarefas To-Do
@route.get("/search", response_model=List[Todo])
def search_todo(name: str = Query(None), db: Session = Depends(get_db)):
query = db.query(model.Todo)
if name:
query = query.filter(model.Todo.title.like(f"%{name}%") | model.Todo.description.like(f"%{name}%"))
todos = query.all()
return todos if todos else {"error": "No post found"}
return []
Esta rota permite pesquisar tarefas pelo título ou descrição. Ela retorna uma lista de tarefas que correspondem aos critérios de pesquisa.
8️⃣ Deletar uma Tarefa To-Do
@route.delete("/delete/{todo_id}")
def delete_post(todo_id: int, db: Session = Depends(get_db)):
todo = db.query(model.Todo).filter(model.Todo.id == todo_id).first()
db.delete(todo)
db.commit()
Esta rota deleta uma tarefa do banco de dados com base no id fornecido.
Executando a API
Passo 7: Executando a API
Para iniciar o servidor, crie um arquivo chamado main.py com o seguinte código:
from fastapi import FastAPI
from route import route
app = FastAPI()
@app.get("/")
def root():
return {"hello": "world!!!"}
app.include_router(route)
Este código cria uma instância do FastAPI, define uma rota raiz (“/”) que retorna uma mensagem de boas-vindas e inclui as rotas definidas no arquivo route.py.
Para executar o servidor, use o seguinte comando:
uvicorn main:app --reload
Abra seu navegador e visite http://127.0.0.1:8000/docs
para testar a API. Você verá a interface interativa do Swagger, que permite testar todos os endpoints da API de forma fácil e intuitiva. Não deixe de conferir as ferramentas para otimizar sua estratégia.
Com este guia, você construiu uma API To-Do com FastAPI, utilizando PostgreSQL e SQLAlchemy. Este projeto é um excelente exemplo para demonstrar suas habilidades e conhecimentos em desenvolvimento backend. Continue explorando e aprimorando suas habilidades para criar aplicações ainda mais robustas e eficientes.
Este conteúdo foi auxiliado por Inteligência Artificiado, mas escrito e revisado por um humano.
Via Dev.to