Skip to main content

📖 Descrição

Endpoint de Server-Sent Events (SSE) que transmite os preços atuais (ask/bid) de cada criptomoeda configurada no Looker, uma vez por segundo. Os preços são lidos diretamente do RealtimePriceCache, que é alimentado em tempo real pelos handlers WebSocket das exchanges.
Os preços dependem do fluxo WebSocket estar habilitado (ENABLED_WEBSOCKET=1). Exchanges não cobertas por WebSocket retornarão eventos com stale: true.

🛠️ Requisição

Método

GET

URL

/v1/lookers/{id}/stream

Parâmetros de Caminho

ParâmetroTipoObrigatórioDescrição
idstringSimID do looker (ObjectID MongoDB)

Headers Necessários

HeaderValor
Accepttext/event-stream
Cache-Controlno-cache

Exemplo de Requisição (curl)

curl --location --no-buffer \
  -H "Accept: text/event-stream" \
  -H "Cache-Control: no-cache" \
  'localhost:8080/v1/lookers/507f1f77bcf86cd799439011/stream'

Exemplo de Requisição (JavaScript)

const lookerId = '507f1f77bcf86cd799439011';
const source = new EventSource(`/v1/lookers/${lookerId}/stream`);

source.onmessage = (event) => {
    const price = JSON.parse(event.data);
    console.log(`${price.ticker} @ ${price.exchange}: ask=${price.ask} bid=${price.bid} stale=${price.stale}`);
};

source.onerror = () => {
    // EventSource reconecta automaticamente
};

// Ao desmontar:
// source.close();

📤 Resposta

Headers da Resposta

HeaderValor
Content-Typetext/event-stream
Cache-Controlno-cache
Connectionkeep-alive
X-Accel-Bufferingno

Frequência de Emissão

A cada 1 segundo, são emitidos N eventos — um por cripto configurada no Looker (máximo 6). Todos os eventos do mesmo ciclo são seguidos de um Flush() para entrega atômica.

Formato dos Eventos SSE

data: {"ticker":"BTC-USDT","exchange":"binance","market":"SPOT","ask":85420.5,"bid":85418.2,"volume":12345.67,"stale":false,"updatedAt":"2026-04-02T14:00:01Z"}

data: {"ticker":"ETH-USDT","exchange":"binance","market":"SPOT","ask":1832.10,"bid":1831.90,"volume":54321.0,"stale":false,"updatedAt":"2026-04-02T14:00:01Z"}

Estrutura do Payload JSON

{
  "ticker": "BTC-USDT",
  "exchange": "binance",
  "market": "SPOT",
  "ask": 85420.50,
  "bid": 85418.20,
  "volume": 12345.67,
  "stale": false,
  "updatedAt": "2026-04-02T14:00:01.000Z"
}

Campos do Payload

CampoTipoDescrição
tickerstringPar de trading em formato BASE-QUOTE (ex: BTC-USDT)
exchangestringNome da exchange onde o Looker monitora essa cripto
marketstringTipo de mercado (SPOT ou FUTURES)
askfloatMelhor preço de venda (ask) atual
bidfloatMelhor preço de compra (bid) atual
volumefloatVolume de 24h (pode ter até 60s de defasagem)
stalebooleantrue quando o dado tem mais de 10s ou a exchange não tem WebSocket
updatedAtstringTimestamp ISO 8601 do último tick recebido

📝 Códigos de Resposta

200 OK + Content-Type: text/event-stream: Stream aberto com sucesso. A conexão permanece aberta até o cliente fechar.
400 Bad Request: id parameter is required — Parâmetro id não informado na URL.
404 Not Found: looker not found — Looker com o ID fornecido não existe no banco.
500 Internal Server Error: SSE not supported by this server ou Failed to load looker.

💡 Integração no Frontend (hook React)

O projeto já fornece o hook useLookerStream em src/hooks/useLookerStream.js:
import { useLookerStream } from 'src/hooks/useLookerStream';

function LookerDetailsPage({ lookerId }) {
    const { prices, connected } = useLookerStream(lookerId);

    return (
        <div>
            {connected ? '🟢 Conectado' : '🔴 Reconectando...'}
            {cryptos.map(crypto => {
                const key = `${crypto.ticker}:${crypto.exchange}`;
                const price = prices[key];
                return (
                    <CryptoCard
                        key={key}
                        crypto={crypto}
                        priceData={price}
                    />
                );
            })}
        </div>
    );
}

Retorno do Hook

PropriedadeTipoDescrição
pricesobjectMapa "ticker:exchange" → payload do evento SSE
connectedbooleantrue enquanto o EventSource estiver aberto

⚠️ Considerações

Quando stale: true, exiba um indicador visual (ícone de aviso, cor diferente) ao usuário para indicar que o dado pode estar desatualizado. O campo é true quando o último tick recebido pelo WebSocket foi há mais de 10 segundos.
Exchanges como Mercado Bitcoin e Novadax não possuem WebSocket público. Para cryptos monitoradas nessas exchanges, todos os eventos terão stale: true. Uma melhoria futura pode adicionar fallback REST com polling de 5s para essas exchanges.
A conexão SSE é mantida até o cliente desconectar (navegação, fechamento de aba). O servidor detecta a desconexão via r.Context().Done() e encerra a goroutine imediatamente, sem leak de recursos.