🧩 Exercícios: Stack FastAPI e Vue 3
Super-Hub: Aplicações Full Stack & Engenharia de Software • Trilha Progressiva em 4 Níveis
🧭 Navegação Pedagógica
-
📖 Teoria do Capítulo 💻 Exemplos 📊 Slides 🧠 Quiz
🎯 Nível 1: Fundamentos
Problema 10.1 — Endpoint Assíncrono no FastAPI com Injeção de Dependência
Contexto: Crie um endpoint @app.get("/items") no FastAPI que receba a sessão do banco assíncrono via db: AsyncSession = Depends(get_db) e retorne uma lista de itens em formato JSON.
Resultado Esperado
from fastapi import FastAPI, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from typing import List
app = FastAPI()
@app.get("/items", response_model=List[ItemResponse])
async def listar_itens(db: AsyncSession = Depends(get_db)):
result = await db.execute(select(ItemModel))
return result.scalars().all()
📤 Instruções de Entrega (Microsoft Teams)
- Salve o arquivo como:
Atividade_10_1_SeuNome.py - Envie na tarefa:
Atividade Cap 10 - Stack FastAPI e Vue 3
🔑 Gabarito de Código & Solução Comentada
O sistema de dependências do FastAPI gerencia o ciclo de vida da conexão com o banco abrindo e fechando a sessão automaticamente.
🎯 Nível 2: Prática
Problema 10.2 — Store do Pinia no Vue 3 com TypeScript
Crie uma Store Pinia useProdutosStore com TypeScript utilizando a sintaxe de setup (defineStore('produtos', () => { ... })) contendo o estado reativo produtos, a propriedade computada totalProdutos e a action assíncrona carregarProdutos().
🔑 Gabarito de Código & Solução Comentada
import { defineStore } from "pinia";
import { ref, computed } from "vue";
import axios from "axios";
export interface Produto { id: number; nome: string; preco: number; }
export const useProdutosStore = defineStore("produtos", () => {
const produtos = ref<Produto[]>([]);
const carregando = ref(false);
const totalProdutos = computed(() => produtos.value.length);
async function carregarProdutos() {
carregando.value = true;
try {
const response = await axios.get<Produto[]>("/api/produtos");
produtos.value = response.data;
} finally {
carregando.value = false;
}
}
return { produtos, carregando, totalProdutos, carregarProdutos };
});
🎯 Nível 3: Integração
Problema 10.3 — Componente Vue 3 SFC com Script Setup e Consumo de API
Implemente um componente Vue 3 (Catalogo.vue) utilizando <script setup lang="ts"> que utilize a store useProdutosStore, renderize o catálogo com formatação de moeda brasileira e exiba um indicador de carregamento enquanto a requisição estiver ativa.
🔑 Gabarito de Código & Solução Comentada
<script setup lang="ts">
import { onMounted } from "vue";
import { useProdutosStore } from "../stores/produtos";
const store = useProdutosStore();
onMounted(() => {
store.carregarProdutos();
});
</script>
<template>
<div class="catalogo-container">
<h2>Catálogo de Produtos ({{ store.totalProdutos }})</h2>
<div v-if="store.carregando" class="spinner">Carregando catálogo...</div>
<div v-else class="grid">
<div v-for="item in store.produtos" :key="item.id" class="card">
<h3>{{ item.nome }}</h3>
<p class="preco">R$ {{ item.preco.toFixed(2) }}</p>
</div>
</div>
</div>
</template>
🎯 Nível 4: Desafio
Problema 10.4 — Integração Full Stack com Autenticação OAuth2 / JWT no FastAPI e Vue
Implemente o endpoint /auth/login no FastAPI utilizando OAuth2PasswordRequestForm que retorne o token de acesso (access_token), e no Vue 3 configure um interceptor do Axios que anexe automaticamente o header Authorization: Bearer <token> em todas as requisições subsequentes.
🔑 Gabarito de Código & Solução Comentada
# Backend FastAPI:
from fastapi.security import OAuth2PasswordRequestForm
@app.post("/auth/login")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
usuario = await autenticar_usuario(form_data.username, form_data.password)
if not usuario:
raise HTTPException(status_code=401, detail="Credenciais inválidas")
token = criar_jwt_token(usuario.id)
return {"access_token": token, "token_type": "bearer"}
// Frontend Vue 3 (Axios Interceptor):
import axios from "axios";
axios.interceptors.request.use((config) => {
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});