APIs com WebSocket e GraphQL
Aula 7 de 7
WebSocket — Comunicação Bidirecional
# Servidor WebSocket (Python + FastAPI)
from fastapi import WebSocket, WebSocketDisconnect
class ConnectionManager:
def __init__(self):
self.active: dict[str, list[WebSocket]] = {}
async def connect(self, websocket: WebSocket, room: str):
await websocket.accept()
self.active.setdefault(room, []).append(websocket)
def disconnect(self, websocket: WebSocket, room: str):
self.active[room].remove(websocket)
async def broadcast(self, room: str, message: dict):
for conn in self.active.get(room, []):
try:
await conn.send_json(message)
except:
pass
manager = ConnectionManager()
@app.websocket("/ws/{room}")
async def websocket_endpoint(websocket: WebSocket, room: str):
await manager.connect(websocket, room)
try:
while True:
data = await websocket.receive_json()
await manager.broadcast(room, data)
except WebSocketDisconnect:
manager.disconnect(websocket, room)
// Cliente WebSocket (JS)
const ws = new WebSocket('wss://api.exemplo.com/ws/sala1');
ws.onopen = () => ws.send(JSON.stringify({type: 'join', user: 'João'}));
ws.onmessage = (event) => console.log(JSON.parse(event.data));
ws.onclose = () => console.log('Desconectado');
Server-Sent Events (SSE)
@app.get("/events")
async def event_stream():
async def generate():
while True:
yield f"data: {json.dumps({'time': time.time()})}\n\n"
await asyncio.sleep(1)
return StreamingResponse(generate(), media_type="text/event-stream")
// Cliente SSE (unidirecional, servidor → cliente)
const events = new EventSource('/events');
events.onmessage = (e) => console.log(JSON.parse(e.data));
events.addEventListener('custom-event', (e) => console.log(e.data));
GraphQL
# Schema GraphQL
type Query {
user(id: ID!): User
users(page: Int, limit: Int): UserConnection!
}
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, input: UpdateUserInput!): User!
deleteUser(id: ID!): Boolean!
}
type User {
id: ID!
name: String!
email: String!
orders: [Order!]!
createdAt: DateTime!
}
type Order {
id: ID!
total: Float!
items: [OrderItem!]!
}
input CreateUserInput {
name: String!
email: String!
password: String!
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
}
Vantagens GraphQL vs REST
| Aspecto | REST | GraphQL |
|---|---|---|
| Over-fetching | Comum (retorna campos não usados) | Cliente pede só o que precisa |
| Under-fetching | Vários requests | Um request, múltiplos recursos |
| Versionamento | URL (/v1/) | Sem versionamento (evolutivo) |
| Tipagem | Opcional (OpenAPI) | Forte (schema nativo) |
| Cache | Nativo (HTTP cache) | Complexo (precisa ferramentas) |
| Tooling | curl, Postman | GraphiQL, Apollo DevTools |
# Query GraphQL (apenas campos necessários)
curl -X POST https://api.exemplo.com/graphql \
-H "Content-Type: application/json" \
-d '{
"query": "query { user(id: \"1\") { name email orders { total } } }"
}'
REST vs GraphQL vs WebSocket
| Protocolo | Melhor para | Pior para |
|---|---|---|
| REST | CRUD, cacheável, simples | Realtime, over-fetching |
| GraphQL | Múltiplos recursos, clientes variados | Cache, upload de arquivo |
| WebSocket | Realtime, jogos, chat | Request-response simples |
| SSE | Notificações unidirecionais | Comunicação bidirecional |
Lab: Escolha do protocolo:
├── Dashboard admin → REST (cache, simples)
├── Feed de notícias → GraphQL (dados relacionais, flexível)
├── Chat → WebSocket (bidirecional, baixa latência)
├── Notificações → SSE (servidor → cliente apenas)
└── Upload CSV → REST (multipart, streaming)
REST é o padrão para CRUD. WebSocket para tempo real bidirecional. GraphQL para flexibilidade de queries. SSE para notificações simples. Não force um protocolo — escolha o certo para o caso.