mina_node_native/http_server/
mod.rs1#[macro_use]
7mod macros;
8mod openapi;
9mod routes;
10mod types;
11
12pub use routes::openapi_spec;
13pub use types::{AppError, AppResult, AppState, JsonErrorResponse};
14
15use mina_node_common::rpc::RpcSender;
16use tokio::net::TcpListener;
17use tower_http::trace::TraceLayer;
18use types::cors_layer;
19
20#[cfg(feature = "swagger-ui")]
21use utoipa_swagger_ui::SwaggerUi;
22
23#[cfg(feature = "scalar")]
24use utoipa_scalar::{Scalar, Servable};
25
26pub async fn run(port: u16, rpc_sender: RpcSender) -> std::io::Result<()> {
30 let state = AppState::new(rpc_sender);
31
32 let trace_layer = TraceLayer::new_for_http()
33 .make_span_with(|request: &axum::http::Request<_>| {
34 tracing::info_span!(
35 "http_request",
36 method = %request.method(),
37 uri = %request.uri(),
38 )
39 })
40 .on_response(
41 |response: &axum::http::Response<_>, latency, span: &tracing::Span| {
42 let status = response.status();
43 if status.is_server_error() || status.is_client_error() {
44 tracing::error!(parent: span, status = %status, latency = ?latency, "request failed");
45 } else {
46 tracing::info!(parent: span, status = %status, latency = ?latency, "request completed");
47 }
48 },
49 );
50
51 let (app, api) = routes::openapi_router().split_for_parts();
53
54 let app = routes::graphql::routes(app);
56
57 #[cfg(feature = "swagger-ui")]
59 let app = app
60 .merge(SwaggerUi::new("/api-docs/swagger-ui").url("/api-docs/openapi.json", api.clone()));
61
62 #[cfg(feature = "scalar")]
63 let app = app.merge(Scalar::with_url("/api-docs/scalar", api));
64
65 #[cfg(feature = "stoplight-elements")]
66 let app = app.route(
67 "/api-docs/stoplight",
68 axum::routing::get(openapi::stoplight_elements),
69 );
70
71 let app = app.layer(trace_layer).layer(cors_layer()).with_state(state);
72
73 let listener = TcpListener::bind(("0.0.0.0", port)).await?;
74 tracing::info!(port, "HTTP server listening");
75 axum::serve(listener, app).await
76}