mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-28 16:49:58 -07:00
global: snapshot
This commit is contained in:
@@ -32,9 +32,10 @@ impl AddressRoutes for ApiRouter<AppState> {
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.address(path.address)).await
|
||||
}, |op| op
|
||||
.id("get_address")
|
||||
.addresses_tag()
|
||||
.summary("Address information")
|
||||
.description("Retrieve comprehensive information about a Bitcoin address including balance, transaction history, UTXOs, and estimated investment metrics. Supports all standard Bitcoin address types (P2PKH, P2SH, P2WPKH, P2WSH, P2TR, etc.).")
|
||||
.description("Retrieve address information including balance and transaction counts. Supports all standard Bitcoin address types (P2PKH, P2SH, P2WPKH, P2WSH, P2TR).\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address)*")
|
||||
.ok_response::<AddressStats>()
|
||||
.not_modified()
|
||||
.bad_request()
|
||||
@@ -52,9 +53,10 @@ impl AddressRoutes for ApiRouter<AppState> {
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.address_txids(path.address, params.after_txid, params.limit)).await
|
||||
}, |op| op
|
||||
.id("get_address_txs")
|
||||
.addresses_tag()
|
||||
.summary("Address transaction IDs")
|
||||
.description("Get transaction IDs for an address, newest first. Use after_txid for pagination.")
|
||||
.description("Get transaction IDs for an address, newest first. Use after_txid for pagination.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-transactions)*")
|
||||
.ok_response::<Vec<Txid>>()
|
||||
.not_modified()
|
||||
.bad_request()
|
||||
@@ -71,9 +73,10 @@ impl AddressRoutes for ApiRouter<AppState> {
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.address_utxos(path.address)).await
|
||||
}, |op| op
|
||||
.id("get_address_utxos")
|
||||
.addresses_tag()
|
||||
.summary("Address UTXOs")
|
||||
.description("Get unspent transaction outputs for an address.")
|
||||
.description("Get unspent transaction outputs (UTXOs) for an address. Returns txid, vout, value, and confirmation status for each UTXO.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-utxo)*")
|
||||
.ok_response::<Vec<Utxo>>()
|
||||
.not_modified()
|
||||
.bad_request()
|
||||
@@ -91,9 +94,10 @@ impl AddressRoutes for ApiRouter<AppState> {
|
||||
// Mempool txs for an address - use MaxAge since it's volatile
|
||||
state.cached_json(&headers, CacheStrategy::MaxAge(5), move |q| q.address_mempool_txids(path.address)).await
|
||||
}, |op| op
|
||||
.id("get_address_mempool_txs")
|
||||
.addresses_tag()
|
||||
.summary("Address mempool transactions")
|
||||
.description("Get unconfirmed transaction IDs for an address from the mempool (up to 50).")
|
||||
.description("Get unconfirmed transaction IDs for an address from the mempool (up to 50).\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-transactions-mempool)*")
|
||||
.ok_response::<Vec<Txid>>()
|
||||
.bad_request()
|
||||
.not_found()
|
||||
@@ -110,9 +114,10 @@ impl AddressRoutes for ApiRouter<AppState> {
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.address_txids(path.address, params.after_txid, 25)).await
|
||||
}, |op| op
|
||||
.id("get_address_confirmed_txs")
|
||||
.addresses_tag()
|
||||
.summary("Address confirmed transactions")
|
||||
.description("Get confirmed transaction IDs for an address, 25 per page. Use ?after_txid=<txid> for pagination.")
|
||||
.description("Get confirmed transaction IDs for an address, 25 per page. Use ?after_txid=<txid> for pagination.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-transactions-chain)*")
|
||||
.ok_response::<Vec<Txid>>()
|
||||
.not_modified()
|
||||
.bad_request()
|
||||
@@ -129,9 +134,10 @@ impl AddressRoutes for ApiRouter<AppState> {
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Static, move |_q| Ok(AddressValidation::from_address(&path.address))).await
|
||||
}, |op| op
|
||||
.id("validate_address")
|
||||
.addresses_tag()
|
||||
.summary("Validate address")
|
||||
.description("Validate a Bitcoin address and get information about its type and scriptPubKey.")
|
||||
.description("Validate a Bitcoin address and get information about its type and scriptPubKey.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-validate)*")
|
||||
.ok_response::<AddressValidation>()
|
||||
.not_modified()
|
||||
),
|
||||
|
||||
@@ -28,9 +28,10 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
.await
|
||||
},
|
||||
|op| {
|
||||
op.blocks_tag()
|
||||
op.id("get_blocks")
|
||||
.blocks_tag()
|
||||
.summary("Recent blocks")
|
||||
.description("Retrieve the last 10 blocks. Returns block metadata for each block.")
|
||||
.description("Retrieve the last 10 blocks. Returns block metadata for each block.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-blocks)*")
|
||||
.ok_response::<Vec<BlockInfo>>()
|
||||
.not_modified()
|
||||
.server_error()
|
||||
@@ -46,10 +47,11 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.block(&path.hash)).await
|
||||
},
|
||||
|op| {
|
||||
op.blocks_tag()
|
||||
op.id("get_block")
|
||||
.blocks_tag()
|
||||
.summary("Block information")
|
||||
.description(
|
||||
"Retrieve block information by block hash. Returns block metadata including height, timestamp, difficulty, size, weight, and transaction count.",
|
||||
"Retrieve block information by block hash. Returns block metadata including height, timestamp, difficulty, size, weight, and transaction count.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-block)*",
|
||||
)
|
||||
.ok_response::<BlockInfo>()
|
||||
.not_modified()
|
||||
@@ -68,10 +70,11 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.block_status(&path.hash)).await
|
||||
},
|
||||
|op| {
|
||||
op.blocks_tag()
|
||||
op.id("get_block_status")
|
||||
.blocks_tag()
|
||||
.summary("Block status")
|
||||
.description(
|
||||
"Retrieve the status of a block. Returns whether the block is in the best chain and, if so, its height and the hash of the next block.",
|
||||
"Retrieve the status of a block. Returns whether the block is in the best chain and, if so, its height and the hash of the next block.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-block-status)*",
|
||||
)
|
||||
.ok_response::<BlockStatus>()
|
||||
.not_modified()
|
||||
@@ -90,10 +93,11 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.block_by_height(path.height)).await
|
||||
},
|
||||
|op| {
|
||||
op.blocks_tag()
|
||||
op.id("get_block_by_height")
|
||||
.blocks_tag()
|
||||
.summary("Block by height")
|
||||
.description(
|
||||
"Retrieve block information by block height. Returns block metadata including hash, timestamp, difficulty, size, weight, and transaction count.",
|
||||
"Retrieve block information by block height. Returns block metadata including hash, timestamp, difficulty, size, weight, and transaction count.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-block-height)*",
|
||||
)
|
||||
.ok_response::<BlockInfo>()
|
||||
.not_modified()
|
||||
@@ -112,10 +116,11 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.blocks(Some(path.height))).await
|
||||
},
|
||||
|op| {
|
||||
op.blocks_tag()
|
||||
op.id("get_blocks_from_height")
|
||||
.blocks_tag()
|
||||
.summary("Blocks from height")
|
||||
.description(
|
||||
"Retrieve up to 10 blocks going backwards from the given height. For example, height=100 returns blocks 100, 99, 98, ..., 91. Height=0 returns only block 0.",
|
||||
"Retrieve up to 10 blocks going backwards from the given height. For example, height=100 returns blocks 100, 99, 98, ..., 91. Height=0 returns only block 0.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-blocks)*",
|
||||
)
|
||||
.ok_response::<Vec<BlockInfo>>()
|
||||
.not_modified()
|
||||
@@ -133,10 +138,11 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.block_txids(&path.hash)).await
|
||||
},
|
||||
|op| {
|
||||
op.blocks_tag()
|
||||
op.id("get_block_txids")
|
||||
.blocks_tag()
|
||||
.summary("Block transaction IDs")
|
||||
.description(
|
||||
"Retrieve all transaction IDs in a block by block hash.",
|
||||
"Retrieve all transaction IDs in a block. Returns an array of txids in block order.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-block-transaction-ids)*",
|
||||
)
|
||||
.ok_response::<Vec<Txid>>()
|
||||
.not_modified()
|
||||
@@ -155,10 +161,11 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.block_txs(&path.hash, path.start_index)).await
|
||||
},
|
||||
|op| {
|
||||
op.blocks_tag()
|
||||
op.id("get_block_txs")
|
||||
.blocks_tag()
|
||||
.summary("Block transactions (paginated)")
|
||||
.description(&format!(
|
||||
"Retrieve transactions in a block by block hash, starting from the specified index. Returns up to {} transactions at a time.",
|
||||
"Retrieve transactions in a block by block hash, starting from the specified index. Returns up to {} transactions at a time.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-block-transactions)*",
|
||||
BLOCK_TXS_PAGE_SIZE
|
||||
))
|
||||
.ok_response::<Vec<Transaction>>()
|
||||
@@ -178,10 +185,11 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
state.cached_text(&headers, CacheStrategy::Height, move |q| q.block_txid_at_index(&path.hash, path.index).map(|t| t.to_string())).await
|
||||
},
|
||||
|op| {
|
||||
op.blocks_tag()
|
||||
op.id("get_block_txid")
|
||||
.blocks_tag()
|
||||
.summary("Transaction ID at index")
|
||||
.description(
|
||||
"Retrieve a single transaction ID at a specific index within a block. Returns plain text txid.",
|
||||
"Retrieve a single transaction ID at a specific index within a block. Returns plain text txid.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-block-transaction-id)*",
|
||||
)
|
||||
.ok_response::<Txid>()
|
||||
.not_modified()
|
||||
@@ -200,9 +208,10 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.block_by_timestamp(path.timestamp)).await
|
||||
},
|
||||
|op| {
|
||||
op.blocks_tag()
|
||||
op.id("get_block_by_timestamp")
|
||||
.blocks_tag()
|
||||
.summary("Block by timestamp")
|
||||
.description("Find the block closest to a given UNIX timestamp.")
|
||||
.description("Find the block closest to a given UNIX timestamp.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-block-timestamp)*")
|
||||
.ok_response::<BlockTimestamp>()
|
||||
.not_modified()
|
||||
.bad_request()
|
||||
@@ -220,10 +229,11 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
state.cached_bytes(&headers, CacheStrategy::Height, move |q| q.block_raw(&path.hash)).await
|
||||
},
|
||||
|op| {
|
||||
op.blocks_tag()
|
||||
op.id("get_block_raw")
|
||||
.blocks_tag()
|
||||
.summary("Raw block")
|
||||
.description(
|
||||
"Returns the raw block data in binary format.",
|
||||
"Returns the raw block data in binary format.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-block-raw)*",
|
||||
)
|
||||
.ok_response::<Vec<u8>>()
|
||||
.not_modified()
|
||||
|
||||
@@ -26,9 +26,10 @@ impl MempoolRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::MaxAge(5), |q| q.mempool_info()).await
|
||||
},
|
||||
|op| {
|
||||
op.mempool_tag()
|
||||
op.id("get_mempool")
|
||||
.mempool_tag()
|
||||
.summary("Mempool statistics")
|
||||
.description("Get current mempool statistics including transaction count, total vsize, and total fees.")
|
||||
.description("Get current mempool statistics including transaction count, total vsize, and total fees.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-mempool)*")
|
||||
.ok_response::<MempoolInfo>()
|
||||
.server_error()
|
||||
},
|
||||
@@ -41,9 +42,10 @@ impl MempoolRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::MaxAge(5), |q| q.mempool_txids()).await
|
||||
},
|
||||
|op| {
|
||||
op.mempool_tag()
|
||||
op.id("get_mempool_txids")
|
||||
.mempool_tag()
|
||||
.summary("Mempool transaction IDs")
|
||||
.description("Get all transaction IDs currently in the mempool.")
|
||||
.description("Get all transaction IDs currently in the mempool.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-mempool-transaction-ids)*")
|
||||
.ok_response::<Vec<Txid>>()
|
||||
.server_error()
|
||||
},
|
||||
@@ -56,9 +58,10 @@ impl MempoolRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::MaxAge(3), |q| q.recommended_fees()).await
|
||||
},
|
||||
|op| {
|
||||
op.mempool_tag()
|
||||
op.id("get_recommended_fees")
|
||||
.mempool_tag()
|
||||
.summary("Recommended fees")
|
||||
.description("Get recommended fee rates for different confirmation targets based on current mempool state.")
|
||||
.description("Get recommended fee rates for different confirmation targets based on current mempool state.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-recommended-fees)*")
|
||||
.ok_response::<RecommendedFees>()
|
||||
.server_error()
|
||||
},
|
||||
@@ -71,9 +74,10 @@ impl MempoolRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::MaxAge(5), |q| q.mempool_blocks()).await
|
||||
},
|
||||
|op| {
|
||||
op.mempool_tag()
|
||||
op.id("get_mempool_blocks")
|
||||
.mempool_tag()
|
||||
.summary("Projected mempool blocks")
|
||||
.description("Get projected blocks from the mempool for fee estimation. Each block contains statistics about transactions that would be included if a block were mined now.")
|
||||
.description("Get projected blocks from the mempool for fee estimation. Each block contains statistics about transactions that would be included if a block were mined now.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-mempool-blocks-fees)*")
|
||||
.ok_response::<Vec<MempoolBlock>>()
|
||||
.server_error()
|
||||
},
|
||||
|
||||
@@ -37,10 +37,12 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Static, |q| Ok(q.metrics_catalog().clone())).await
|
||||
},
|
||||
|op| op
|
||||
.id("get_metrics_tree")
|
||||
.metrics_tag()
|
||||
.summary("Metrics catalog")
|
||||
.description(
|
||||
"Returns the complete hierarchical catalog of available metrics organized as a tree structure. Metrics are grouped by categories and subcategories. Best viewed in an interactive JSON viewer (e.g., Firefox's built-in JSON viewer) for easy navigation of the nested structure."
|
||||
"Returns the complete hierarchical catalog of available metrics organized as a tree structure. \
|
||||
Metrics are grouped by categories and subcategories."
|
||||
)
|
||||
.ok_response::<TreeNode>()
|
||||
.not_modified(),
|
||||
@@ -56,9 +58,10 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Static, |q| Ok(q.metric_count())).await
|
||||
},
|
||||
|op| op
|
||||
.id("get_metrics_count")
|
||||
.metrics_tag()
|
||||
.summary("Metric count")
|
||||
.description("Current metric count")
|
||||
.description("Returns the number of metrics available per index type.")
|
||||
.ok_response::<Vec<MetricCount>>()
|
||||
.not_modified(),
|
||||
),
|
||||
@@ -73,6 +76,7 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Static, |q| Ok(q.indexes().to_vec())).await
|
||||
},
|
||||
|op| op
|
||||
.id("get_indexes")
|
||||
.metrics_tag()
|
||||
.summary("List available indexes")
|
||||
.description(
|
||||
@@ -93,9 +97,10 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Static, move |q| Ok(q.metrics(pagination))).await
|
||||
},
|
||||
|op| op
|
||||
.id("list_metrics")
|
||||
.metrics_tag()
|
||||
.summary("Metrics list")
|
||||
.description("Paginated list of available metrics")
|
||||
.description("Paginated flat list of all available metric names. Use `page` query param for pagination.")
|
||||
.ok_response::<PaginatedMetrics>()
|
||||
.not_modified(),
|
||||
),
|
||||
@@ -112,6 +117,7 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Static, move |q| Ok(q.match_metric(&path.metric, query.limit))).await
|
||||
},
|
||||
|op| op
|
||||
.id("search_metrics")
|
||||
.metrics_tag()
|
||||
.summary("Search metrics")
|
||||
.description("Fuzzy search for metrics by name. Supports partial matches and typos.")
|
||||
@@ -136,10 +142,11 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
|
||||
}).await
|
||||
},
|
||||
|op| op
|
||||
.id("get_metric_info")
|
||||
.metrics_tag()
|
||||
.summary("Get supported indexes for a metric")
|
||||
.description(
|
||||
"Returns the list of indexes are supported by the specified metric. \
|
||||
"Returns the list of indexes supported by the specified metric. \
|
||||
For example, `realized_price` might be available on dateindex, weekindex, and monthindex."
|
||||
)
|
||||
.ok_response::<Vec<Index>>()
|
||||
@@ -166,6 +173,7 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
|
||||
.await
|
||||
},
|
||||
|op| op
|
||||
.id("get_metric")
|
||||
.metrics_tag()
|
||||
.summary("Get metric data")
|
||||
.description(
|
||||
@@ -183,11 +191,12 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
|
||||
get_with(
|
||||
bulk::handler,
|
||||
|op| op
|
||||
.id("get_metrics")
|
||||
.metrics_tag()
|
||||
.summary("Bulk metric data")
|
||||
.description(
|
||||
"Fetch multiple metrics in a single request. Supports filtering by index and date range. \
|
||||
Returns an array of MetricData objects."
|
||||
Returns an array of MetricData objects. For a single metric, use `get_metric` instead."
|
||||
)
|
||||
.ok_response::<Vec<MetricData>>()
|
||||
.csv_response()
|
||||
|
||||
@@ -32,9 +32,10 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Height, |q| q.difficulty_adjustment()).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
op.id("get_difficulty_adjustment")
|
||||
.mining_tag()
|
||||
.summary("Difficulty adjustment")
|
||||
.description("Get current difficulty adjustment information including progress through the current epoch, estimated retarget date, and difficulty change prediction.")
|
||||
.description("Get current difficulty adjustment information including progress through the current epoch, estimated retarget date, and difficulty change prediction.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-difficulty-adjustment)*")
|
||||
.ok_response::<DifficultyAdjustment>()
|
||||
.not_modified()
|
||||
.server_error()
|
||||
@@ -49,9 +50,10 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Static, |q| Ok(q.all_pools())).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
op.id("get_pools")
|
||||
.mining_tag()
|
||||
.summary("List all mining pools")
|
||||
.description("Get list of all known mining pools with their identifiers.")
|
||||
.description("Get list of all known mining pools with their identifiers.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-mining-pools)*")
|
||||
.ok_response::<Vec<PoolInfo>>()
|
||||
.not_modified()
|
||||
.server_error()
|
||||
@@ -65,9 +67,10 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("{:?}", path.time_period)), move |q| q.mining_pools(path.time_period)).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
op.id("get_pool_stats")
|
||||
.mining_tag()
|
||||
.summary("Mining pool statistics")
|
||||
.description("Get mining pool statistics for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y")
|
||||
.description("Get mining pool statistics for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-mining-pools)*")
|
||||
.ok_response::<PoolsSummary>()
|
||||
.not_modified()
|
||||
.server_error()
|
||||
@@ -81,9 +84,10 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(path.slug), move |q| q.pool_detail(path.slug)).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
op.id("get_pool")
|
||||
.mining_tag()
|
||||
.summary("Mining pool details")
|
||||
.description("Get detailed information about a specific mining pool including block counts and shares for different time periods.")
|
||||
.description("Get detailed information about a specific mining pool including block counts and shares for different time periods.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-mining-pool)*")
|
||||
.ok_response::<PoolDetail>()
|
||||
.not_modified()
|
||||
.not_found()
|
||||
@@ -98,9 +102,10 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::height_with("hashrate"), |q| q.hashrate(None)).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
op.id("get_hashrate")
|
||||
.mining_tag()
|
||||
.summary("Network hashrate (all time)")
|
||||
.description("Get network hashrate and difficulty data for all time.")
|
||||
.description("Get network hashrate and difficulty data for all time.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-hashrate)*")
|
||||
.ok_response::<HashrateSummary>()
|
||||
.not_modified()
|
||||
.server_error()
|
||||
@@ -114,9 +119,10 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("hashrate-{:?}", path.time_period)), move |q| q.hashrate(Some(path.time_period))).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
op.id("get_hashrate_by_period")
|
||||
.mining_tag()
|
||||
.summary("Network hashrate")
|
||||
.description("Get network hashrate and difficulty data for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y")
|
||||
.description("Get network hashrate and difficulty data for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-hashrate)*")
|
||||
.ok_response::<HashrateSummary>()
|
||||
.not_modified()
|
||||
.server_error()
|
||||
@@ -130,9 +136,10 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::height_with("diff-adj"), |q| q.difficulty_adjustments(None)).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
op.id("get_difficulty_adjustments")
|
||||
.mining_tag()
|
||||
.summary("Difficulty adjustments (all time)")
|
||||
.description("Get historical difficulty adjustments. Returns array of [timestamp, height, difficulty, change_percent].")
|
||||
.description("Get historical difficulty adjustments including timestamp, block height, difficulty value, and percentage change.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-difficulty-adjustments)*")
|
||||
.ok_response::<Vec<DifficultyAdjustmentEntry>>()
|
||||
.not_modified()
|
||||
.server_error()
|
||||
@@ -146,9 +153,10 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("diff-adj-{:?}", path.time_period)), move |q| q.difficulty_adjustments(Some(path.time_period))).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
op.id("get_difficulty_adjustments_by_period")
|
||||
.mining_tag()
|
||||
.summary("Difficulty adjustments")
|
||||
.description("Get historical difficulty adjustments for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y. Returns array of [timestamp, height, difficulty, change_percent].")
|
||||
.description("Get historical difficulty adjustments for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-difficulty-adjustments)*")
|
||||
.ok_response::<Vec<DifficultyAdjustmentEntry>>()
|
||||
.not_modified()
|
||||
.server_error()
|
||||
@@ -162,9 +170,10 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("fees-{:?}", path.time_period)), move |q| q.block_fees(path.time_period)).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
op.id("get_block_fees")
|
||||
.mining_tag()
|
||||
.summary("Block fees")
|
||||
.description("Get average block fees for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y")
|
||||
.description("Get average block fees for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-block-fees)*")
|
||||
.ok_response::<Vec<BlockFeesEntry>>()
|
||||
.not_modified()
|
||||
.server_error()
|
||||
@@ -178,32 +187,34 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("rewards-{:?}", path.time_period)), move |q| q.block_rewards(path.time_period)).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
op.id("get_block_rewards")
|
||||
.mining_tag()
|
||||
.summary("Block rewards")
|
||||
.description("Get average block rewards (coinbase = subsidy + fees) for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y")
|
||||
.description("Get average block rewards (coinbase = subsidy + fees) for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-block-rewards)*")
|
||||
.ok_response::<Vec<BlockRewardsEntry>>()
|
||||
.not_modified()
|
||||
.server_error()
|
||||
},
|
||||
),
|
||||
)
|
||||
// TODO: Disabled - dateindex doesn't have percentile fields (see block_fee_rates.rs)
|
||||
// .api_route(
|
||||
// "/api/v1/mining/blocks/fee-rates/{time_period}",
|
||||
// get_with(
|
||||
// async |headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
// state.cached_json(&headers, CacheStrategy::height_with(format!("feerates-{:?}", path.time_period)), move |q| q.block_fee_rates(path.time_period)).await
|
||||
// },
|
||||
// |op| {
|
||||
// op.mining_tag()
|
||||
// .summary("Block fee rates")
|
||||
// .description("Get block fee rate percentiles (min, 10th, 25th, median, 75th, 90th, max) for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y")
|
||||
// .ok_response::<Vec<BlockFeeRatesEntry>>()
|
||||
// .not_modified()
|
||||
// .server_error()
|
||||
// },
|
||||
// ),
|
||||
// )
|
||||
.api_route(
|
||||
"/api/v1/mining/blocks/fee-rates/{time_period}",
|
||||
get_with(
|
||||
async |Path(_path): Path<TimePeriodParam>| {
|
||||
axum::Json(serde_json::json!({
|
||||
"status": "wip",
|
||||
"message": "This endpoint is work in progress. Percentile fields are not yet available."
|
||||
}))
|
||||
},
|
||||
|op| {
|
||||
op.id("get_block_fee_rates")
|
||||
.mining_tag()
|
||||
.summary("Block fee rates (WIP)")
|
||||
.description("**Work in progress.** Get block fee rate percentiles (min, 10th, 25th, median, 75th, 90th, max) for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-block-feerates)*")
|
||||
.ok_response::<serde_json::Value>()
|
||||
},
|
||||
),
|
||||
)
|
||||
.api_route(
|
||||
"/api/v1/mining/blocks/sizes-weights/{time_period}",
|
||||
get_with(
|
||||
@@ -211,9 +222,10 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("sizes-{:?}", path.time_period)), move |q| q.block_sizes_weights(path.time_period)).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
op.id("get_block_sizes_weights")
|
||||
.mining_tag()
|
||||
.summary("Block sizes and weights")
|
||||
.description("Get average block sizes and weights for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y")
|
||||
.description("Get average block sizes and weights for a time period. Valid periods: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-sizes-weights)*")
|
||||
.ok_response::<BlockSizesWeights>()
|
||||
.not_modified()
|
||||
.server_error()
|
||||
@@ -227,9 +239,10 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("reward-stats-{}", path.block_count)), move |q| q.reward_stats(path.block_count)).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
op.id("get_reward_stats")
|
||||
.mining_tag()
|
||||
.summary("Mining reward statistics")
|
||||
.description("Get mining reward statistics for the last N blocks including total rewards, fees, and transaction count.")
|
||||
.description("Get mining reward statistics for the last N blocks including total rewards, fees, and transaction count.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-reward-stats)*")
|
||||
.ok_response::<RewardStats>()
|
||||
.not_modified()
|
||||
.server_error()
|
||||
|
||||
@@ -58,7 +58,8 @@ impl ApiRoutes for ApiRouter<AppState> {
|
||||
.await
|
||||
},
|
||||
|op| {
|
||||
op.server_tag()
|
||||
op.id("get_version")
|
||||
.server_tag()
|
||||
.summary("API version")
|
||||
.description("Returns the current version of the API server")
|
||||
.ok_response::<String>()
|
||||
@@ -77,7 +78,8 @@ impl ApiRoutes for ApiRouter<AppState> {
|
||||
})
|
||||
},
|
||||
|op| {
|
||||
op.server_tag()
|
||||
op.id("get_health")
|
||||
.server_tag()
|
||||
.summary("Health check")
|
||||
.description("Returns the health status of the API server")
|
||||
.ok_response::<Health>()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use aide::openapi::{Info, OpenApi, Tag};
|
||||
use aide::openapi::{Contact, Info, License, OpenApi, Tag};
|
||||
|
||||
//
|
||||
// https://docs.rs/schemars/latest/schemars/derive.JsonSchema.html
|
||||
@@ -18,10 +18,40 @@ pub fn create_openapi() -> OpenApi {
|
||||
let info = Info {
|
||||
title: "Bitcoin Research Kit".to_string(),
|
||||
description: Some(
|
||||
"API for querying Bitcoin blockchain data including addresses, transactions, and chain statistics. This API provides low-level access to indexed blockchain data with advanced analytics capabilities."
|
||||
r#"API for querying Bitcoin blockchain data and on-chain metrics.
|
||||
|
||||
### Features
|
||||
|
||||
- **Metrics**: Thousands of time-series metrics across multiple indexes (date, block height, etc.)
|
||||
- **[Mempool.space](https://mempool.space/docs/api/rest) compatible** (WIP): Most non-metrics endpoints follow the mempool.space API format
|
||||
- **Multiple formats**: JSON and CSV output
|
||||
|
||||
### Client Libraries
|
||||
|
||||
- [JavaScript/TypeScript](https://www.npmjs.com/package/brk-client)
|
||||
- [Python](https://pypi.org/project/brk-client/)
|
||||
- [Rust](https://crates.io/crates/brk_client)
|
||||
|
||||
### Links
|
||||
|
||||
- [GitHub](https://github.com/bitcoinresearchkit/brk)
|
||||
- [Bitview](https://bitview.space) - Web app built on this API"#
|
||||
.to_string(),
|
||||
),
|
||||
version: format!("v{VERSION}"),
|
||||
contact: Some(Contact {
|
||||
name: Some("Bitcoin Research Kit".to_string()),
|
||||
url: Some("https://github.com/bitcoinresearchkit/brk".to_string()),
|
||||
email: Some("hello@bitcoinresearchkit.org".to_string()),
|
||||
..Contact::default()
|
||||
}),
|
||||
license: Some(License {
|
||||
name: "MIT".to_string(),
|
||||
url: Some(
|
||||
"https://github.com/bitcoinresearchkit/brk/blob/main/docs/LICENSE.md".to_string(),
|
||||
),
|
||||
..License::default()
|
||||
}),
|
||||
..Info::default()
|
||||
};
|
||||
|
||||
@@ -29,8 +59,8 @@ pub fn create_openapi() -> OpenApi {
|
||||
Tag {
|
||||
name: "Metrics".to_string(),
|
||||
description: Some(
|
||||
"Access Bitcoin network metrics and time-series data. Query historical statistics \
|
||||
across various indexes with JSON or CSV output."
|
||||
"Access thousands of Bitcoin network metrics and time-series data. Query historical statistics \
|
||||
across various indexes (date, week, month, block height) with JSON or CSV output."
|
||||
.to_string(),
|
||||
),
|
||||
..Default::default()
|
||||
@@ -39,7 +69,8 @@ pub fn create_openapi() -> OpenApi {
|
||||
name: "Blocks".to_string(),
|
||||
description: Some(
|
||||
"Retrieve block data by hash or height. Access block headers, transaction lists, \
|
||||
and raw block bytes."
|
||||
and raw block bytes.\n\n\
|
||||
*[Mempool.space](https://mempool.space/docs/api/rest) compatible (WIP).*"
|
||||
.to_string(),
|
||||
),
|
||||
..Default::default()
|
||||
@@ -48,7 +79,8 @@ pub fn create_openapi() -> OpenApi {
|
||||
name: "Transactions".to_string(),
|
||||
description: Some(
|
||||
"Retrieve transaction data by txid. Access full transaction details, confirmation \
|
||||
status, raw hex, and output spend information."
|
||||
status, raw hex, and output spend information.\n\n\
|
||||
*[Mempool.space](https://mempool.space/docs/api/rest) compatible (WIP).*"
|
||||
.to_string(),
|
||||
),
|
||||
..Default::default()
|
||||
@@ -57,7 +89,8 @@ pub fn create_openapi() -> OpenApi {
|
||||
name: "Addresses".to_string(),
|
||||
description: Some(
|
||||
"Query Bitcoin address data including balances, transaction history, and UTXOs. \
|
||||
Supports all address types: P2PKH, P2SH, P2WPKH, P2WSH, and P2TR."
|
||||
Supports all address types: P2PKH, P2SH, P2WPKH, P2WSH, and P2TR.\n\n\
|
||||
*[Mempool.space](https://mempool.space/docs/api/rest) compatible (WIP).*"
|
||||
.to_string(),
|
||||
),
|
||||
..Default::default()
|
||||
@@ -66,7 +99,8 @@ pub fn create_openapi() -> OpenApi {
|
||||
name: "Mempool".to_string(),
|
||||
description: Some(
|
||||
"Monitor unconfirmed transactions and fee estimates. Get mempool statistics, \
|
||||
transaction IDs, and recommended fee rates for different confirmation targets."
|
||||
transaction IDs, and recommended fee rates for different confirmation targets.\n\n\
|
||||
*[Mempool.space](https://mempool.space/docs/api/rest) compatible (WIP).*"
|
||||
.to_string(),
|
||||
),
|
||||
..Default::default()
|
||||
@@ -75,7 +109,8 @@ pub fn create_openapi() -> OpenApi {
|
||||
name: "Mining".to_string(),
|
||||
description: Some(
|
||||
"Mining statistics including pool distribution, hashrate, difficulty adjustments, \
|
||||
block rewards, and fee rates across configurable time periods."
|
||||
block rewards, and fee rates across configurable time periods.\n\n\
|
||||
*[Mempool.space](https://mempool.space/docs/api/rest) compatible (WIP).*"
|
||||
.to_string(),
|
||||
),
|
||||
..Default::default()
|
||||
|
||||
@@ -31,10 +31,11 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.transaction(txid)).await
|
||||
},
|
||||
|op| op
|
||||
.id("get_tx")
|
||||
.transactions_tag()
|
||||
.summary("Transaction information")
|
||||
.description(
|
||||
"Retrieve complete transaction data by transaction ID (txid). Returns the full transaction details including inputs, outputs, and metadata. The transaction data is read directly from the blockchain data files.",
|
||||
"Retrieve complete transaction data by transaction ID (txid). Returns inputs, outputs, fee, size, and confirmation status.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-transaction)*",
|
||||
)
|
||||
.ok_response::<Transaction>()
|
||||
.not_modified()
|
||||
@@ -54,10 +55,11 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.transaction_status(txid)).await
|
||||
},
|
||||
|op| op
|
||||
.id("get_tx_status")
|
||||
.transactions_tag()
|
||||
.summary("Transaction status")
|
||||
.description(
|
||||
"Retrieve the confirmation status of a transaction. Returns whether the transaction is confirmed and, if so, the block height, hash, and timestamp.",
|
||||
"Retrieve the confirmation status of a transaction. Returns whether the transaction is confirmed and, if so, the block height, hash, and timestamp.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-transaction-status)*",
|
||||
)
|
||||
.ok_response::<TxStatus>()
|
||||
.not_modified()
|
||||
@@ -77,10 +79,11 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
state.cached_text(&headers, CacheStrategy::Height, move |q| q.transaction_hex(txid)).await
|
||||
},
|
||||
|op| op
|
||||
.id("get_tx_hex")
|
||||
.transactions_tag()
|
||||
.summary("Transaction hex")
|
||||
.description(
|
||||
"Retrieve the raw transaction as a hex-encoded string. Returns the serialized transaction in hexadecimal format.",
|
||||
"Retrieve the raw transaction as a hex-encoded string. Returns the serialized transaction in hexadecimal format.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-transaction-hex)*",
|
||||
)
|
||||
.ok_response::<Hex>()
|
||||
.not_modified()
|
||||
@@ -101,10 +104,11 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.outspend(txid, path.vout)).await
|
||||
},
|
||||
|op| op
|
||||
.id("get_tx_outspend")
|
||||
.transactions_tag()
|
||||
.summary("Output spend status")
|
||||
.description(
|
||||
"Get the spending status of a transaction output. Returns whether the output has been spent and, if so, the spending transaction details.",
|
||||
"Get the spending status of a transaction output. Returns whether the output has been spent and, if so, the spending transaction details.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-transaction-outspend)*",
|
||||
)
|
||||
.ok_response::<TxOutspend>()
|
||||
.not_modified()
|
||||
@@ -124,10 +128,11 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.outspends(txid)).await
|
||||
},
|
||||
|op| op
|
||||
.id("get_tx_outspends")
|
||||
.transactions_tag()
|
||||
.summary("All output spend statuses")
|
||||
.description(
|
||||
"Get the spending status of all outputs in a transaction. Returns an array with the spend status for each output.",
|
||||
"Get the spending status of all outputs in a transaction. Returns an array with the spend status for each output.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-transaction-outspends)*",
|
||||
)
|
||||
.ok_response::<Vec<TxOutspend>>()
|
||||
.not_modified()
|
||||
|
||||
Reference in New Issue
Block a user