Expand description
§brk_server
HTTP server providing REST API access to Bitcoin analytics data
brk_server
provides a high-performance HTTP server that exposes BRK’s indexed blockchain data and computed analytics through a comprehensive REST API. It offers multiple output formats, intelligent caching, compression, and optional web interface serving.
URL: https://bitview.space/api
§What it provides
- REST API: Vector-based data access with flexible querying and pagination
- Multiple Output Formats: JSON, CSV, TSV, and Markdown table formatting
- Performance Features: ETag caching, compression, and request weight limiting
- Web Interface: Optional static file serving for web applications
- MCP Integration: Model Context Protocol support for LLM integration
§Key Features
§API Capabilities
- Direct vector access: Single vector queries with index-to-ID pattern
- Multi-vector queries: Query multiple datasets simultaneously
- Flexible pagination: Positive/negative indexing with range queries
- Format negotiation: Multiple output formats based on use case
§Performance Features
- ETag caching: Conditional requests with 304 Not Modified responses
- Compression: Brotli, Gzip, Zstd, Deflate support with automatic negotiation
- Request weight limiting: Protects against oversized queries (max 320,000 weight)
- In-memory caching: 10,000-item cache with 50ms guard timeout
§HTTP Features
- Auto port assignment: Starts from port 3110, increments if busy
- CORS enabled: Cross-origin requests for web clients
- Tracing middleware: Colored request/response logging
- Static file serving: Optional website hosting
§Usage
§Basic Server Setup
use brk_server::Server;
use brk_interface::Interface;
use brk_indexer::Indexer;
use brk_computer::Computer;
// Load data sources
let indexer = Indexer::forced_import("./brk_data")?;
let computer = Computer::forced_import("./brk_data", &indexer, None)?;
// Create interface and server
let interface = Interface::build(&indexer, &computer);
let server = Server::new(interface, Some("./website".into()));
// Start server (with MCP support)
server.serve(true).await?;
§API Access Patterns
§Single Vector Queries
# Latest 100 price values
curl "https://bitview.space/api/vecs/date-to-close?from=-100"
# First 50 difficulty values as CSV
curl "https://bitview.space/api/vecs/height-to-difficulty?count=50&format=csv"
# Range from block 800,000 to 800,100
curl "https://bitview.space/api/vecs/height-to-timestamp?from=800000&to=800100"
§Multi-Vector Queries
# Multiple price metrics for last 30 days
curl "https://bitview.space/api/vecs/query?index=date&ids=open,high,low,close&from=-30&format=csv"
# Block statistics for specific range
curl "https://bitview.space/api/vecs/query?index=height&ids=size,weight,tx_count,fee_sum&from=800000&count=100"
# Weekly analytics as JSON matrix
curl "https://bitview.space/api/vecs/query?index=week&ids=close,difficulty&from=-52"
§API Reference
§Vector Metadata Endpoints
Endpoint | Description |
---|---|
GET /api/vecs/index-count | Total number of available indexes |
GET /api/vecs/id-count | Total number of vector IDs |
GET /api/vecs/vec-count | Total vectors (all index/ID combinations) |
GET /api/vecs/indexes | List of all available indexes |
GET /api/vecs/accepted-indexes | Mapping of indexes to accepted variants |
GET /api/vecs/ids?page=N | Paginated vector IDs (1000/page) |
GET /api/vecs/index-to-ids?index=INDEX&page=N | IDs supporting given index |
GET /api/vecs/id-to-indexes?id=ID | Indexes supported by given ID |
§Vector Data Access
§Direct Access Pattern
GET /api/vecs/{INDEX}-to-{ID}
# Examples
curl "/api/vecs/height-to-timestamp"
curl "/api/vecs/date-to-close"
curl "/api/vecs/month-to-supply"
§Multi-Vector Query
GET /api/vecs/query
Required Parameters:
index
: Vector index type (height, date, week, month, etc.)ids
: Comma or space-separated vector IDs
Optional Parameters:
from
(i64): Start index (negative = from end, default: 0)to
(i64): End index (exclusive, negative = from end)count
(usize): Maximum number of resultsformat
: Output format (json
,csv
,tsv
,md
)
§Response Types
Single Value (one vector, one result):
42.5
Array (one vector, multiple results):
[42.5, 43.1, 44.2]
Matrix (multiple vectors):
[
[42.5, 43.1, 44.2],
[1500, 1520, 1480],
[0.05, 0.052, 0.048]
]
CSV Format:
index,close,supply,fee_rate
0,42.5,1500,0.05
1,43.1,1520,0.052
2,44.2,1480,0.048
§System Endpoints
Endpoint | Description |
---|---|
GET /version | Server version information |
GET /health | Health check with timestamp |
GET /api | API documentation redirect |
GET /* | Static file serving (if enabled) |
§Configuration
§Server State
pub struct AppState {
interface: &'static Interface<'static>, // Data access interface
path: Option<PathBuf>, // Static files path
cache: Arc<Cache<String, Bytes>>, // Response cache
}
§Middleware Stack
- Compression Layer: Brotli, Gzip, Zstd, Deflate
- Response URI Layer: Adds URI to response extensions for logging
- Trace Layer: Request/response logging with colored output
§Caching Strategy
- ETag generation: Based on data content and query parameters
- Conditional requests: 304 Not Modified for unchanged data
- In-memory cache: 10,000 items with LRU eviction
- Cache headers:
Cache-Control: must-revalidate
§Performance Characteristics
§Request Weight System
- Weight calculation: Based on data range size and complexity
- Weight limit: 320,000 units per request
- Protection: Prevents oversized queries that could impact performance
§Compression
- Automatic negotiation: Based on
Accept-Encoding
header - Multiple algorithms: Brotli (best), Zstd, Gzip, Deflate
- Transparent: Applied automatically to all responses
§Logging
- Colored output: Green for 200, red for errors, gray for redirects
- Request timing: Latency measurement and display
- Status tracking: HTTP status codes with appropriate colors
§Dependencies
axum
- High-performance async web frameworktower-http
- HTTP middleware (compression, tracing, CORS)brk_interface
- Data access and formatting layerbrk_mcp
- Model Context Protocol routesquick_cache
- Fast in-memory cachingtokio
- Async runtime for networking
This README was generated by Claude Code
§Example
use std::{path::Path, thread::sleep, time::Duration};
use bitcoincore_rpc::RpcApi;
use brk_computer::Computer;
use brk_error::Result;
use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_interface::Interface;
use brk_parser::Parser;
use brk_server::Server;
use vecdb::Exit;
pub fn main() -> Result<()> {
brk_logger::init(Some(Path::new(".log")))?;
let process = true;
let bitcoin_dir = Path::new("");
let brk_dir = Path::new("");
let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new(
"http://localhost:8332",
bitcoincore_rpc::Auth::CookieFile(bitcoin_dir.join(".cookie")),
)?));
let exit = Exit::new();
exit.set_ctrlc_handler();
let parser = Parser::new(bitcoin_dir.join("blocks"), Some(brk_dir.to_path_buf()), rpc);
let outputs_dir = Path::new("../../_outputs");
let mut indexer = Indexer::forced_import(outputs_dir)?;
let fetcher = Some(Fetcher::import(true, None)?);
let mut computer = Computer::forced_import(outputs_dir, &indexer, fetcher)?;
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()?
.block_on(async {
let interface = Interface::build(&indexer, &computer);
let server = Server::new(interface, None);
let server = tokio::spawn(async move {
server.serve(true).await.unwrap();
});
if process {
loop {
let block_count = rpc.get_block_count()?;
let starting_indexes = indexer.index(&parser, rpc, &exit, true)?;
computer.compute(&indexer, starting_indexes, &exit)?;
while block_count == rpc.get_block_count()? {
sleep(Duration::from_secs(1))
}
}
}
#[allow(unreachable_code)]
server.await.unwrap();
Ok(())
})
}