Skip to main content

sentrystr_api/
lib.rs

1//! # SentryStr API
2//!
3//! REST API server for SentryStr event collection and querying.
4//!
5//! ## Quick Start
6//!
7//! ```rust
8//! use sentrystr_api::create_app;
9//!
10//! #[tokio::main]
11//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
12//!     let _app = create_app();
13//!     println!("SentryStr API server would run on http://localhost:3000");
14//!     Ok(())
15//! }
16//! ```
17//!
18//! ## API Endpoints
19//!
20//! ### GET /events
21//! Query events with optional filters:
22//! ```bash
23//! curl "http://localhost:3000/events?limit=10&level=error"
24//! curl "http://localhost:3000/events?author=npub1...&since=2024-01-01T00:00:00Z"
25//! ```
26//!
27//! ### GET /events/{author}
28//! Get events by specific author:
29//! ```bash
30//! curl "http://localhost:3000/events/npub1abc123.../events"
31//! ```
32//!
33//! ### GET /health
34//! Health check endpoint:
35//! ```bash
36//! curl "http://localhost:3000/health"
37//! ```
38//!
39//! ## With Tracing Integration
40//!
41//! ```rust
42//! use sentrystr_api::create_app;
43//!
44//! #[tokio::main]
45//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
46//!     let _app = create_app();
47//!     println!("Starting SentryStr API server");
48//!     Ok(())
49//! }
50//! ```
51
52pub mod api;
53pub mod handlers;
54pub mod models;
55
56pub use api::create_app;
57pub use handlers::*;
58pub use models::*;
59
60pub type Result<T> = std::result::Result<T, ApiError>;
61
62#[derive(Debug)]
63pub enum ApiError {
64    Collection(String),
65    Internal(String),
66    BadRequest(String),
67}
68
69impl std::fmt::Display for ApiError {
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        match self {
72            ApiError::Collection(msg) => write!(f, "Collection error: {}", msg),
73            ApiError::Internal(msg) => write!(f, "Internal error: {}", msg),
74            ApiError::BadRequest(msg) => write!(f, "Bad request: {}", msg),
75        }
76    }
77}
78
79impl std::error::Error for ApiError {}
80
81impl axum::response::IntoResponse for ApiError {
82    fn into_response(self) -> axum::response::Response {
83        let (status, error_message) = match self {
84            ApiError::Collection(msg) => (axum::http::StatusCode::INTERNAL_SERVER_ERROR, msg),
85            ApiError::Internal(msg) => (axum::http::StatusCode::INTERNAL_SERVER_ERROR, msg),
86            ApiError::BadRequest(msg) => (axum::http::StatusCode::BAD_REQUEST, msg),
87        };
88
89        let body = serde_json::json!({
90            "error": error_message
91        });
92
93        (status, axum::Json(body)).into_response()
94    }
95}