Este tutorial mostra como criar uma API Web de tarefas usando FastAPI, Python 3.13 e uv para gerenciamento de dependências. Abordaremos desde a documentação inicial até a implementação dos endpoints e testes via Swagger.
mkdir fastapi-todo && cd fastapi-todo
uv
:uv init --app
uv add fastapi --extra standard
fastapi-todo/
├── pyproject.toml
└── app/
└── main.py
uv run fastapi dev
Isso gerencia dependências, cria o ambiente virtual e executa a aplicação1.
Endpoint | Método | URI | Descrição | Dados de Entrada | Retorno Esperado | Status Code |
---|---|---|---|---|---|---|
Listar tarefas | GET | /tasks | Lista todas as tarefas | Query: skip, limit (opcional) | Lista de tarefas | 200 |
Obter tarefa por ID | GET | /tasks/{task_id} | Detalha uma tarefa específica | Parâmetro de URL: task_id | Tarefa | 200 |
Criar nova tarefa | POST | /tasks | Cria uma nova tarefa | Corpo: título, descrição, status | Tarefa criada | 201 |
Atualizar tarefa | PUT | /tasks/{task_id} | Atualiza uma tarefa existente | Parâmetro de URL: task_id, corpo | Tarefa atualizada | 200 |
Deletar tarefa | DELETE | /tasks/{task_id} | Remove uma tarefa | Parâmetro de URL: task_id | Mensagem de sucesso | 204 |
Vamos definir os modelos para entrada e saída de dados:
from pydantic import BaseModel
from typing import Optional
from datetime import datetime
class TaskCreate(BaseModel):
title: str
description: Optional[str] = None
completed: bool = False
class Task(TaskCreate):
id: str
created_at: datetime
title
: str — título da tarefadescription
: Optional[str] — descrição opcionalcompleted
: bool — status de conclusãoid
: str — identificador únicocreated_at
: datetime — data de criação2No arquivo app/main.py
:
from fastapi import FastAPI, HTTPException, Query, Path, status
from typing import List, Optional
from uuid import uuid4
from datetime import datetime
from pydantic import BaseModel
class TaskCreate(BaseModel):
title: str
description: Optional[str] = None
completed: bool = False
class Task(TaskCreate):
id: str
created_at: datetime
app = FastAPI(
title="API de Tarefas",
description="API para gestão de tarefas a fazer",
version="0.1.0"
)
# Simulação de banco de dados em memória
tasks_db = {}
@app.get("/tasks", response_model=List[Task], status_code=status.HTTP_200_OK)
def list_tasks(skip: int = Query(0, ge=0), limit: int = Query(10, gt=0)):
"""
Lista tarefas com paginação via query string.
"""
tasks = list(tasks_db.values())
return tasks[skip: skip + limit]
@app.get("/tasks/{task_id}", response_model=Task, status_code=status.HTTP_200_OK)
def get_task(task_id: str = Path(...)):
"""
Busca uma tarefa pelo ID via parâmetro de URL.
"""
task = tasks_db.get(task_id)
if not task:
raise HTTPException(status_code=404, detail="Tarefa não encontrada")
return task
@app.post("/tasks", response_model=Task, status_code=status.HTTP_201_CREATED)
def create_task(task: TaskCreate):
"""
Cria uma nova tarefa via corpo da requisição.
"""
task_id = str(uuid4())
new_task = Task(id=task_id, created_at=datetime.utcnow(), **task.dict())
tasks_db[task_id] = new_task
return new_task
@app.put("/tasks/{task_id}", response_model=Task, status_code=status.HTTP_200_OK)
def update_task(task_id: str, task: TaskCreate):
"""
Atualiza uma tarefa existente.
"""
stored_task = tasks_db.get(task_id)
if not stored_task:
raise HTTPException(status_code=404, detail="Tarefa não encontrada")
updated_task = Task(id=task_id, created_at=stored_task.created_at, **task.dict())
tasks_db[task_id] = updated_task
return updated_task
@app.delete("/tasks/{task_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_task(task_id: str):
"""
Remove uma tarefa.
"""
if task_id in tasks_db:
del tasks_db[task_id]
else:
raise HTTPException(status_code=404, detail="Tarefa não encontrada")
skip
, limit
em /tasks
para paginação3.task_id
em /tasks/{task_id}
.TaskCreate
em POST/PUT.response_model
nos decorators.status_code
nos decorators4.Ao rodar a aplicação, acesse:
http://127.0.0.1:8000/docs
Com isso, você tem uma API de tarefas pronta para evoluir!
https://dev.to/jamesbmour/part-2-building-a-todo-api-with-fastapi-step-by-step-guide-3042 ↩
https://www.oneloop.ai/blog/understanding-query-params-headers-and-body-params-in-fastapi-when-to-use-each ↩
https://stackoverflow.com/questions/62705219/in-pythons-fastapi-autogenerated-openapi-swagger-documentation-page-how-can-i ↩ ↩2