REST API em FastAPI com autenticacao JWT, login Google, persistencia em PostgreSQL e resposta de chat em streaming.
- Base URL local:
http://localhost:8000 - Swagger:
http://localhost:8000/docs
Endpoints protegidos exigem header:
Authorization: Bearer <access_token>Fluxo recomendado:
POST /auth/register(opcional para criar conta).POST /auth/loginouPOST /auth/google.- Usar
access_tokennas chamadas protegidas.
{
"detail": "Human-readable message"
}POST /auth/register
Cria conta por email/senha.
Request:
{
"email": "user@example.com",
"password": "minimum6chars"
}Responses:
201 Created
{
"id": "uuid",
"email": "user@example.com",
"created_at": "2026-03-15T14:00:00.000000+00:00"
}409email ja cadastrado422payload invalido503DB indisponivel
POST /auth/login
Request:
{
"email": "user@example.com",
"password": "your-password"
}Response 200:
{
"access_token": "jwt-token",
"token_type": "bearer"
}Erros comuns:
401credenciais invalidas422payload invalido503DB indisponivel
POST /auth/token
Body: application/x-www-form-urlencoded
username: emailpassword: senha
Resposta igual a /auth/login.
POST /auth/google
Request:
{
"id_token": "google-id-token"
}Comportamento:
- Valida
id_tokenno endpointhttps://oauth2.googleapis.com/tokeninfo. - Verifica
audigual aGOOGLE_CLIENT_ID. - Exige email verificado.
- Cria usuario automaticamente se não existir.
Response 200:
{
"access_token": "jwt-token",
"token_type": "bearer"
}Erros comuns:
401token invalido ou email não verificado503Google auth não configurado ou servico indisponivel
POST /conversations (protegido)
Request:
{
"title": "Minha conversa"
}title pode ser null.
Response 201:
{
"id": "uuid",
"title": "Minha conversa",
"created_at": "2026-03-15T14:05:00.000000+00:00"
}GET /conversations (protegido)
Response 200:
[
{
"id": "uuid",
"title": "Minha conversa",
"created_at": "2026-03-15T14:05:00.000000+00:00"
}
]GET /conversations/{conversation_id} (protegido)
Response 200:
[
{
"id": "uuid",
"role": "user",
"content": "Pergunta",
"created_at": "2026-03-15T14:10:00.000000+00:00"
},
{
"id": "uuid",
"role": "assistant",
"content": "Resposta",
"created_at": "2026-03-15T14:10:03.000000+00:00"
}
]Erros:
404conversa não encontrada
DELETE /conversations/{conversation_id} (protegido)
Response 204 No Content.
Erros:
404conversa não encontrada
POST /chat (autenticado ou anonimo)
Request:
{
"conversation_id": "uuid-opcional",
"history": [
{ "role": "user", "content": "Pergunta anterior" },
{ "role": "assistant", "content": "Resposta anterior" }
],
"question": "Quais sinais podem indicar alergia a medicamentos?"
}Response 200:
Content-Type: text/plain- corpo em streaming (chunked)
Nao retorna JSON nesse endpoint. O cliente deve ler stream incrementalmente.
Comportamentos relevantes:
- Com token JWT: usa
conversation_id, busca historico no banco e persiste novas mensagens. - Sem token: aceita chat anonimo e usa
historyenviado pelo cliente como contexto. - Se autenticado e titulo estiver vazio/untitled, gera titulo automaticamente por LLM.
Erros:
400quando autenticado semconversation_id404conversa não encontrada422payload invalido
const response = await fetch('http://localhost:8000/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
body: JSON.stringify({
conversation_id: conversationId, // opcional em modo anonimo
history: localHistory, // opcional, usado no modo anonimo
question: message,
}),
})
if (!response.ok || !response.body) {
throw new Error('Chat request failed')
}
const reader = response.body.getReader()
const decoder = new TextDecoder()
let fullText = ''
while (true) {
const { done, value } = await reader.read()
if (done) break
fullText += decoder.decode(value, { stream: true })
}- Prefira usar as rotas proxy do frontend (
web/app/api/*) para evitar expor URL interna da API no browser. - O token JWT atual não possui refresh token; refaca login quando expirar.
- Para login Google em ambiente local, configure origem
http://localhost:3000no Google Cloud.