Skip to content
This repository was archived by the owner on Jan 2, 2026. It is now read-only.

Commit 55aa96a

Browse files
committed
feat: first endpoint: /healthz
1 parent 8e02e97 commit 55aa96a

File tree

5 files changed

+77
-7
lines changed

5 files changed

+77
-7
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ serde_with = "3.13.0"
2929
thiserror = "2.0.12"
3030
chrono = "0.4.41"
3131
bigdecimal = "0.4.8"
32+
serde_json = "1.0.140"
3233

3334
[dev-dependencies]
3435
tokio-test = "0.4"

src/api/mod.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,66 @@
22
// License, v. 2.0. If a copy of the MPL was not distributed with this
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

5+
use log::info;
6+
use poem::http::{Method, StatusCode};
7+
use poem::listener::TcpListener;
8+
use poem::middleware::{Cors, NormalizePath};
9+
use poem::web::Json;
10+
use poem::{EndpointExt, IntoResponse, Response, Route, Server, handler};
11+
use serde_json::json;
12+
13+
use crate::config::ApiConfig;
14+
use crate::database::Database;
15+
516
/// Admin-only functionality.
617
pub(super) mod admin;
18+
19+
#[allow(clippy::expect_used)]
20+
/// Build the API [Route]s and start a `tokio::task`, which is a poem [Server] processing incoming
21+
/// HTTP API requests.
22+
pub(super) fn start_api(api_config: ApiConfig, db: Database) -> tokio::task::JoinHandle<()> {
23+
let routes = Route::new()
24+
.at("/healthz", healthz)
25+
.nest("/.p2/core/", setup_p2_core_routes())
26+
.with(NormalizePath::new(poem::middleware::TrailingSlash::Trim))
27+
.with(Cors::new().allow_methods(&[
28+
Method::CONNECT,
29+
Method::GET,
30+
Method::POST,
31+
Method::PUT,
32+
Method::DELETE,
33+
Method::PATCH,
34+
Method::OPTIONS,
35+
]))
36+
.catch_all_error(custom_error)
37+
.data(db);
38+
39+
let handle = tokio::task::spawn(async move {
40+
Server::new(TcpListener::bind((api_config.host.as_str().trim(), api_config.port)))
41+
.run(routes)
42+
.await
43+
.expect("Failed to start HTTP server");
44+
log::info!("HTTP Server stopped");
45+
});
46+
info!("Started HTTP API server");
47+
handle
48+
}
49+
50+
/// Catch-all fallback error.
51+
async fn custom_error(err: poem::Error) -> impl IntoResponse {
52+
Json(json! ({
53+
"success": false,
54+
"message": err.to_string(),
55+
}))
56+
.with_status(err.status())
57+
}
58+
59+
#[handler]
60+
fn healthz() -> impl IntoResponse {
61+
Response::builder().status(StatusCode::OK).finish()
62+
}
63+
64+
/// All routes under `/.p2/core/`.
65+
fn setup_p2_core_routes() -> Route {
66+
Route::new()
67+
}

src/config/mod.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const TLS_CONFIG_VERIFY_CA: &str = "verify_ca";
2626
/// PostgreSQL: TLS Required with TLS certificate authority and subject verification
2727
const TLS_CONFIG_VERIFY_FULL: &str = "verify_full";
2828

29-
#[derive(Deserialize, Debug)]
29+
#[derive(Deserialize, Debug, Clone)]
3030
/// The `sonata.toml` configuration file as Rust structs.
3131
pub struct SonataConfig {
3232
/// API module configuration
@@ -37,7 +37,7 @@ pub struct SonataConfig {
3737
pub general: GeneralConfig,
3838
}
3939

40-
#[derive(Deserialize, Debug)]
40+
#[derive(Deserialize, Debug, Clone)]
4141
/// API Module configuration
4242
pub struct ApiConfig {
4343
#[serde(flatten)]
@@ -53,7 +53,7 @@ impl Deref for ApiConfig {
5353
}
5454
}
5555

56-
#[derive(Deserialize, Debug)]
56+
#[derive(Deserialize, Debug, Clone)]
5757
/// Gateway module configuration
5858
pub struct GatewayConfig {
5959
#[serde(flatten)]
@@ -69,15 +69,15 @@ impl Deref for GatewayConfig {
6969
}
7070
}
7171

72-
#[derive(Deserialize, Debug)]
72+
#[derive(Deserialize, Debug, Clone)]
7373
/// General configuration, consisting of database configuration
7474
pub struct GeneralConfig {
7575
/// Database configuration, including host, port, password, etc.
7676
pub database: DatabaseConfig,
7777
}
7878

7979
#[serde_as]
80-
#[derive(Deserialize, Debug)]
80+
#[derive(Deserialize, Debug, Clone)]
8181
pub struct DatabaseConfig {
8282
/// How many connections to allocate for this connection pool at maximum.
8383
/// PostgreSQLs default value is 100.
@@ -98,7 +98,7 @@ pub struct DatabaseConfig {
9898
pub tls: TlsConfig,
9999
}
100100

101-
#[derive(Deserialize, Debug)]
101+
#[derive(Deserialize, Debug, Clone)]
102102
pub struct ComponentConfig {
103103
/// Whether this component is enabled.
104104
pub enabled: bool,
@@ -129,7 +129,7 @@ impl SonataConfig {
129129
}
130130
}
131131

132-
#[derive(Debug, Deserialize, Default)]
132+
#[derive(Debug, Deserialize, Default, Clone)]
133133
/// TLS configuration modes. Also called `sslconfig` by PostgreSQL. See <https://www.postgresql.org/docs/current/libpq-ssl.html#:~:text=32.1.%C2%A0SSL%20Mode-,descriptions,-sslmode>
134134
/// for the security implications of this choice.
135135
pub enum TlsConfig {

src/main.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ async fn main() -> StdResult<()> {
117117
_ => (),
118118
};
119119

120+
let mut tasks =
121+
vec![api::start_api(SonataConfig::get_or_panic().api.clone(), database.clone())];
122+
123+
for task in tasks.into_iter() {
124+
task.await.unwrap()
125+
}
126+
120127
Ok(())
121128
}
122129

0 commit comments

Comments
 (0)