server: add support for /api/X-to-Y + fix query cli + add meta api endpoints

This commit is contained in:
nym21
2025-06-08 20:30:53 +02:00
parent e0bf1d736f
commit be492d5084
11 changed files with 311 additions and 132 deletions
+24 -7
View File
@@ -41,19 +41,35 @@ The API uses `brk_query` and so inherites all of its features including formats.
### API
#### `GET /api/vecs/indexes`
#### [`GET /api/vecs/index-count`](https://bitcoinresearchkit.org/api/vecs/index-count)
Count of all possible indexes
#### [`GET /api/vecs/id-count`](https://bitcoinresearchkit.org/api/vecs/id-count)
Count of all possible ids
#### [`GET /api/vecs/variant-count`](https://bitcoinresearchkit.org/api/vecs/variant-count)
Count of all possible variants
#### [`GET /api/vecs/indexes`](https://bitcoinresearchkit.org/api/vecs/indexes)
A list of all possible vec indexes and their accepted variants
#### `GET /api/vecs/ids`
#### [`GET /api/vecs/ids`](https://bitcoinresearchkit.org/api/vecs/ids)
A list of all possible vec ids
#### `GET /api/vecs/id-to-indexes`
#### [`GET /api/vecs/variants`](https://bitcoinresearchkit.org/api/vecs/variants)
A list of all possible variants
#### [`GET /api/vecs/id-to-indexes`](https://bitcoinresearchkit.org/api/vecs/id-to-indexes)
A list of all possible vec ids and their supported vec indexes
#### `GET /api/vecs/index-to-ids`
#### [`GET /api/vecs/index-to-ids`](https://bitcoinresearchkit.org/api/vecs/index-to-ids)
A list of all possible vec indexes and their supported vec ids
@@ -67,8 +83,9 @@ This endpoint retrieves data based on the specified vector index and values.
| --- | --- | --- | --- |
| `index` | `VecIndex` | Yes | The vector index to query. |
| `values` | `VecId[]` | Yes | A comma or space-separated list of vector IDs to retrieve. |
| `from` | `unsigned int` | No | The starting index for pagination (default is 0). |
| `to` | `unsigned int` | No | The ending index for pagination (default is the total number of results). |
| `from` | `signed int` | No | Inclusive starting index for pagination (default is 0). |
| `to` | `signed int` | No | Exclusive ending index for pagination (default is the total number of results). Overrides `count` |
| `count` | `unsigned int` | No | The number of values requested |
| `format` | `string` | No | The format of the response. Options include `json`, `csv`, `tsv`, or `md` (default is `json`). |
**Examples:**
@@ -80,7 +97,7 @@ GET /api/query?index=week&values=ohlc,block-interval-average&from=0&to=20&format
### Meta
#### `GET /version`
#### [`GET /version`](https://bitcoinresearchkit.org/version)
The version of the server and thus BRK.
+89 -23
View File
@@ -1,11 +1,13 @@
use std::collections::BTreeMap;
use axum::{
Router,
extract::State,
Json, Router,
extract::{Path, Query, State},
http::HeaderMap,
response::{IntoResponse, Redirect, Response},
routing::get,
};
use brk_query::{Params, ParamsOpt};
use super::AppState;
@@ -20,24 +22,29 @@ pub trait ApiRoutes {
impl ApiRoutes for Router<AppState> {
fn add_api_routes(self) -> Self {
self.route(
"/api",
get(|| async {
Redirect::permanent(
"https://github.com/bitcoinresearchkit/brk/tree/main/crates/brk_server#api",
)
}),
)
.route("/api/query", get(query::handler))
.route("/api/vecs/ids", get(vecids_handler))
.route("/api/vecs/indexes", get(vecindexes_handler))
.route("/api/vecs/id-to-indexes", get(vecid_to_vecindexes_handler))
.route("/api/vecs/index-to-ids", get(vecindex_to_vecids_handler))
self.route("/api/query", get(query::handler))
.route("/api/vecs/id-count", get(id_count_handler))
.route("/api/vecs/index-count", get(index_count_handler))
.route("/api/vecs/variant-count", get(variant_count_handler))
.route("/api/vecs/ids", get(ids_handler))
.route("/api/vecs/indexes", get(indexes_handler))
.route("/api/vecs/variants", get(variants_handler))
.route("/api/vecs/id-to-indexes", get(id_to_indexes_handler))
.route("/api/vecs/index-to-ids", get(index_to_ids_handler))
.route("/api/{variant}", get(variant_handler))
.route(
"/api",
get(|| async {
Redirect::temporary(
"https://github.com/bitcoinresearchkit/brk/tree/main/crates/brk_server#api",
)
}),
)
}
}
pub async fn vecids_handler(State(app_state): State<AppState>) -> Response {
axum::Json(
pub async fn ids_handler(State(app_state): State<AppState>) -> Response {
Json(
app_state
.query
.vec_trees
@@ -48,8 +55,29 @@ pub async fn vecids_handler(State(app_state): State<AppState>) -> Response {
.into_response()
}
pub async fn vecindexes_handler(State(app_state): State<AppState>) -> Response {
axum::Json(
pub async fn variant_count_handler(State(app_state): State<AppState>) -> Response {
Json(
app_state
.query
.vec_trees
.index_to_id_to_vec
.values()
.map(|tree| tree.len())
.sum::<usize>(),
)
.into_response()
}
pub async fn id_count_handler(State(app_state): State<AppState>) -> Response {
Json(app_state.query.vec_trees.id_to_index_to_vec.keys().count()).into_response()
}
pub async fn index_count_handler(State(app_state): State<AppState>) -> Response {
Json(app_state.query.vec_trees.index_to_id_to_vec.keys().count()).into_response()
}
pub async fn indexes_handler(State(app_state): State<AppState>) -> Response {
Json(
app_state
.query
.vec_trees
@@ -61,10 +89,48 @@ pub async fn vecindexes_handler(State(app_state): State<AppState>) -> Response {
.into_response()
}
pub async fn vecid_to_vecindexes_handler(State(app_state): State<AppState>) -> Response {
axum::Json(app_state.query.vec_trees.serialize_id_to_index_to_vec()).into_response()
pub async fn variants_handler(State(app_state): State<AppState>) -> Response {
Json(
app_state
.query
.vec_trees
.index_to_id_to_vec
.iter()
.flat_map(|(index, id_to_vec)| {
let index_ser = index.serialize_long();
id_to_vec
.keys()
.map(|id| format!("{}-to-{}", index_ser, id))
.collect::<Vec<_>>()
})
.collect::<Vec<_>>(),
)
.into_response()
}
pub async fn vecindex_to_vecids_handler(State(app_state): State<AppState>) -> Response {
axum::Json(app_state.query.vec_trees.serialize_index_to_id_to_vec()).into_response()
pub async fn id_to_indexes_handler(State(app_state): State<AppState>) -> Response {
Json(app_state.query.vec_trees.serialize_id_to_index_to_vec()).into_response()
}
pub async fn index_to_ids_handler(State(app_state): State<AppState>) -> Response {
Json(app_state.query.vec_trees.serialize_index_to_id_to_vec()).into_response()
}
const TO_SEPARATOR: &str = "-to-";
pub async fn variant_handler(
headers: HeaderMap,
Path(variant): Path<String>,
Query(params_opt): Query<ParamsOpt>,
state: State<AppState>,
) -> Response {
let mut split = variant.split(TO_SEPARATOR);
let params = Params::from((
(
split.next().unwrap().to_string(),
split.collect::<Vec<_>>().join(TO_SEPARATOR),
),
params_opt,
));
query::handler(headers, Query(params), state).await
}
+5 -17
View File
@@ -37,30 +37,14 @@ pub async fn handler(
fn req_to_response_res(
headers: HeaderMap,
AxumQuery(Params {
format,
from,
index,
mut to,
count,
values,
rest,
}): AxumQuery<Params>,
AppState { query, .. }: AppState,
) -> color_eyre::Result<Response> {
let index = Index::try_from(index.as_str())?;
if to.is_none() {
if let Some(c) = count {
let c = c as i64;
if let Some(f) = from {
if f.is_positive() || f.abs() > c {
to.replace(f + c);
}
} else {
to.replace(c);
}
}
}
let vecs = query.search(
index,
&values.iter().map(|v| v.as_str()).collect::<Vec<_>>(),
@@ -70,6 +54,10 @@ fn req_to_response_res(
return Ok(Json(vec![] as Vec<usize>).into_response());
}
let from = rest.from();
let to = rest.to();
let format = rest.format();
let weight = vecs
.iter()
.map(|(_, v)| {