Разработка API для доступа к собранным данным
Мы разрабатываем REST и WebSocket API для доступа к собранным крипто-данным. Исторические транзакции, funding rates, gas prices — всё это должно быть доступно с минимальной задержкой и стабильной производительностью. Наш опыт в блокчейн-разработке позволяет создавать API, которые выдерживают нагрузку тысяч запросов в секунду и не раскрывают лишнего.
Какие проблемы решает правильно спроектированное API?
Сырые данные с бирж и блокчейнов — это хаос. Без продуманного API вы столкнётесь с тремя типичными проблемами: нестабильная пагинация при добавлении новых записей, высокая задержка при time-series запросах и отсутствие контроля доступа. Мы решаем их через cursor-пагинацию, многоуровневое кеширование и API-ключи с rate limiting.
Как мы строим архитектуру?
Используем Fastify (Node.js) для REST и WebSocket, Redis для кеша и rate limiting, PostgreSQL или ClickHouse для хранения данных. Стандартные практики: версионирование через URL (/v1/), ISO 8601 для времени, поле ?fields= для выбора колонок.
REST эндпоинты проектируем под конкретные сценарии: funding rates, транзакции, новости. Каждый эндпоинт поддерживает cursor-пагинацию, которая стабильна при вставке новых данных — в отличие от offset-пагинации.
Пример валидации с помощью Zod:
import { z } from "zod"; const FundingRatesQuerySchema = z.object({ symbol: z.string().regex(/^[A-Z]+-[A-Z]+$/, "Invalid symbol format"), exchange: z.enum(["binance", "bybit", "okx", "hyperliquid"]).optional(), from: z.coerce.date(), to: z.coerce.date(), limit: z.coerce.number().min(1).max(1000).default(100), cursor: z.string().optional(), }); Ранний возврат 400 с детальными ошибками экономит время клиентов.
| Эндпоинт | Описание | Метод |
|---|---|---|
/v1/funding-rates |
Исторические ставки финансирования | GET |
/v1/transactions/{chain}/{address} |
Исторические транзакции по адресу | GET |
/v1/news |
Новостная лента по тегам | GET |
/v1/gas/history |
История газовых цен | GET |
/v1/stream |
Real-time поток данных | WebSocket |
Почему многоуровневое кеширование критично для крипто-данных?
Крипто-данные делятся на исторические (неизменяемые) и real-time. Исторические можно кешировать надолго, real-time — лишь на секунды. Мы используем три уровня:
| Уровень | Что кеширует | TTL |
|---|---|---|
| CDN | Статичные исторические данные | 1 час |
| Redis | Результаты частых запросов | 30 с – 5 мин |
| База данных (read replica) | Все остальное | — |
Redis-кеш строится по ключу запроса. Пример:
async function getFundingRates(query: FundingRatesQuery): Promise<FundingRateRecord[]> { const cacheKey = `fr:${query.symbol}:${query.exchange ?? "all"}:${query.from.getTime()}:${query.to.getTime()}`; const cached = await redis.get(cacheKey); if (cached) return JSON.parse(cached); const data = await db.queryFundingRates(query); const ttl = query.to < new Date(Date.now() - 3600_000) ? 3600 : 30; await redis.setEx(cacheKey, ttl, JSON.stringify(data)); return data; } Для time-series запросов в PostgreSQL используем покрывающие индексы:
CREATE INDEX CONCURRENTLY idx_funding_rates_lookup ON funding_rates (symbol, exchange, settled_at DESC) INCLUDE (funding_rate, mark_price); Для аналитики (агрегации, средние) ClickHouse быстрее PostgreSQL в 5–10 раз.
Как реализовать real-time поток?
WebSocket-сервер на Fastify подписывает клиентов на каналы событий. Heartbeat каждые 30 секунд отсекает зависшие соединения.
fastify.get("/v1/stream", { websocket: true }, (socket, req) => { const subscriptions = parseSubscriptions(req.query); const unsubscribers = subscriptions.map((sub) => eventBus.on(sub.channel, (data) => { if (socket.readyState === WebSocket.OPEN) { socket.send(JSON.stringify({ channel: sub.channel, data })); } }) ); socket.on("message", (msg) => { const cmd = JSON.parse(msg.toString()); if (cmd.type === "subscribe") { /* ... */ } if (cmd.type === "unsubscribe") { /* ... */ } if (cmd.type === "ping") socket.send(JSON.stringify({ type: "pong" })); }); socket.on("close", () => unsubscribers.forEach(unsub => unsub())); }); Как обеспечить безопасность и контроль доступа?
Используем API-ключи вместо JWT — они проще в управлении. Rate limiting на основе sliding window с Lua-скриптом в Redis:
local key = KEYS[1] local limit = tonumber(ARGV[1]) local window = tonumber(ARGV[2]) local now = tonumber(ARGV[3]) redis.call("ZREMRANGEBYSCORE", key, 0, now - window) local count = redis.call("ZCARD", key) if count >= limit then return 0 end redis.call("ZADD", key, now, now) redis.call("EXPIRE", key, window / 1000) return 1 В ответах клиент видит заголовки X-RateLimit-* — может адаптировать своё поведение.
Мониторинг и observability
Для production API необходим сбор метрик в реальном времени. Мы подключаем Prometheus с набором стандартных счётчиков: количество запросов по методу и маршруту, P50/P95/P99 latency, процент ошибок (4xx и 5xx), текущее количество WebSocket-соединений. Grafana-дашборд показывает нагрузку в разрезе эндпоинтов — сразу видно, какой запрос начал тормозить.
Алертинг настраиваем через Alertmanager: P99 latency выше 500 мс, error rate выше 1%, Redis недоступен, очередь WebSocket-событий растёт. Такая система позволяет выявлять узкие места до того, как клиенты замечают деградацию. Среднее время реакции на инцидент при настроенном мониторинге — до 2 минут.
Структурированное логирование (JSON) через pino даёт возможность агрегировать ошибки по типу запроса и API-ключу. Это критично при отладке: видно, кто и что запрашивает, где пагинация ломается, почему клиент получает 400 вместо 200. Логи отправляются в Loki или Elasticsearch — в зависимости от инфраструктуры. Retention политика: детальные логи 7 дней, агрегированные метрики — 90 дней.
Что входит в разработку API под ключ?
- Проектирование схемы эндпоинтов и пагинации
- Реализация REST + WebSocket на Fastify
- Интеграция с Redis и ClickHouse/PostgreSQL
- Аутентификация через API-ключи и rate limiting
- Написание OpenAPI документации
- Мониторинг с Prometheus и Grafana (P99 latency, request rate)
Срок разработки — 4–7 недель в зависимости от числа источников данных и требований к производительности. Стоимость рассчитывается индивидуально после анализа объёма данных и требований к масштабированию.
Пишите — оценим ваш проект и предложим конкретную архитектуру.







