api.rs 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. //! REST API over a `Ledger`. Everything is read-only: the dashboard observes
  2. //! the ledger, it does not mutate it. All monetary values are emitted as
  3. //! minor-unit strings (the native `Cent` serialization); clients format them
  4. //! using the asset registry from `/api/assets`.
  5. //!
  6. //! These handlers are thin wrappers over the shared builders in [`crate::data`];
  7. //! the server-rendered HTML views in [`crate::ui`] read from the same builders.
  8. use axum::{
  9. Json, Router,
  10. extract::{Path, Query, State},
  11. routing::get,
  12. };
  13. use kuatia_core::AccountId;
  14. use serde::Deserialize;
  15. use crate::assets::AssetMeta;
  16. use crate::data::{
  17. AccountDetailDto, AccountDto, ApiError, AppState, EventDto, OverviewDto, TransferDto,
  18. };
  19. /// Build the `/api` router.
  20. pub fn router(state: AppState) -> Router {
  21. Router::new()
  22. .route("/assets", get(assets))
  23. .route("/overview", get(overview))
  24. .route("/accounts", get(accounts))
  25. .route("/accounts/{uuid}", get(account_detail))
  26. .route("/transfers", get(transfers))
  27. .route("/events", get(events))
  28. .with_state(state)
  29. }
  30. async fn assets(State(state): State<AppState>) -> Json<Vec<AssetMeta>> {
  31. Json((*state.assets).clone())
  32. }
  33. async fn overview(State(state): State<AppState>) -> Result<Json<OverviewDto>, ApiError> {
  34. Ok(Json(crate::data::overview(&state).await?))
  35. }
  36. async fn accounts(State(state): State<AppState>) -> Result<Json<Vec<AccountDto>>, ApiError> {
  37. Ok(Json(crate::data::accounts(&state).await?))
  38. }
  39. async fn account_detail(
  40. State(state): State<AppState>,
  41. Path(uuid): Path<String>,
  42. ) -> Result<Json<AccountDetailDto>, ApiError> {
  43. let id: AccountId = uuid.parse().map_err(ApiError::bad_request)?;
  44. Ok(Json(crate::data::account_detail(&state, id).await?))
  45. }
  46. #[derive(Deserialize)]
  47. struct TransfersParams {
  48. limit: Option<u32>,
  49. }
  50. async fn transfers(
  51. State(state): State<AppState>,
  52. Query(params): Query<TransfersParams>,
  53. ) -> Result<Json<Vec<TransferDto>>, ApiError> {
  54. Ok(Json(crate::data::transfers(&state, params.limit).await?))
  55. }
  56. #[derive(Deserialize)]
  57. struct EventsParams {
  58. after: Option<u64>,
  59. limit: Option<u32>,
  60. }
  61. async fn events(
  62. State(state): State<AppState>,
  63. Query(params): Query<EventsParams>,
  64. ) -> Result<Json<Vec<EventDto>>, ApiError> {
  65. Ok(Json(
  66. crate::data::events(
  67. &state,
  68. params.after.unwrap_or(0),
  69. params.limit.unwrap_or(200),
  70. )
  71. .await?,
  72. ))
  73. }