kb.erickguedes.com
APIs: Design, Arquitetura e Implementação

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

AspectoRESTGraphQL
Over-fetchingComum (retorna campos não usados)Cliente pede só o que precisa
Under-fetchingVários requestsUm request, múltiplos recursos
VersionamentoURL (/v1/)Sem versionamento (evolutivo)
TipagemOpcional (OpenAPI)Forte (schema nativo)
CacheNativo (HTTP cache)Complexo (precisa ferramentas)
Toolingcurl, PostmanGraphiQL, 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

ProtocoloMelhor paraPior para
RESTCRUD, cacheável, simplesRealtime, over-fetching
GraphQLMúltiplos recursos, clientes variadosCache, upload de arquivo
WebSocketRealtime, jogos, chatRequest-response simples
SSENotificações unidirecionaisComunicaçã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.