Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions pdp-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use log::{error, info};
use std::net::SocketAddr;
use utoipa::OpenApi;
use utoipa_axum::router::OpenApiRouter;
use utoipa_scalar::{Scalar, Servable};

#[tokio::main]
async fn main() {
Expand All @@ -39,7 +38,6 @@ async fn main() {
std::process::exit(1);
}
};

// Initialize application state
let state: AppState = AppState::with_existing_cache(&config, cache)
.await
Expand Down Expand Up @@ -78,14 +76,13 @@ async fn main() {
/// Create a new application instance with a given state
pub async fn create_app(state: AppState) -> Router {
// Create OpenAPI documentation
let (openapi_router, api_doc) =
OpenApiRouter::with_openapi(openapi::ApiDoc::openapi()).split_for_parts();
let openapi_router = OpenApiRouter::with_openapi(openapi::ApiDoc::openapi());

// Create base router with routes
Router::new()
.merge(api::router(&state))
.merge(openapi_router)
.merge(Scalar::with_url("/scalar", api_doc.clone()))
.merge(crate::openapi::router())
.with_state(state)
}

Expand Down
98 changes: 98 additions & 0 deletions pdp-server/src/openapi.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
use crate::state::AppState;
use axum::body::Body;
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::{extract::State, routing::get, Router};
use http::HeaderValue;
use utoipa::OpenApi;

pub(crate) const HEALTH_TAG: &str = "Health API";
Expand All @@ -17,3 +23,95 @@ pub(crate) const AUTHZEN_TAG: &str = "AuthZen API";
)
)]
pub(crate) struct ApiDoc;

/// Handler for the OpenAPI JSON specification endpoint
async fn openapi_json_handler(State(state): State<AppState>) -> impl IntoResponse {
let openapi_url = state.config.horizon.get_url("/openapi.json");

match state.horizon_client.get(&openapi_url).send().await {
Ok(response) => match response.bytes().await {
Ok(bytes) => match serde_json::from_slice::<serde_json::Value>(&bytes) {
Ok(json) => axum::Json(json).into_response(),
Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Invalid JSON").into_response(),
},
Err(_) => {
(StatusCode::INTERNAL_SERVER_ERROR, "Failed to read response").into_response()
}
},
Err(_) => (
StatusCode::SERVICE_UNAVAILABLE,
"Horizon service unavailable",
)
.into_response(),
}
}

/// Handler for the ReDoc documentation endpoint
async fn redoc_handler(State(state): State<AppState>) -> impl IntoResponse {
let redoc_url = state.config.horizon.get_url("/redoc");

match state.horizon_client.get(&redoc_url).send().await {
Ok(response) => {
// Extract content-type header before consuming the response
let content_type = response
.headers()
.get("content-type")
.unwrap_or(&HeaderValue::from_static("text/html"))
.clone();

match response.text().await {
Ok(text) => Response::builder()
.header("content-type", content_type)
.body(Body::from(text))
.unwrap(),
Err(_) => {
(StatusCode::INTERNAL_SERVER_ERROR, "Failed to read response").into_response()
}
}
}
Err(_) => (
StatusCode::SERVICE_UNAVAILABLE,
"Horizon service unavailable",
)
.into_response(),
}
}

/// Handler for the Scalar documentation endpoint
async fn scalar_handler(State(state): State<AppState>) -> impl IntoResponse {
let scalar_url = state.config.horizon.get_url("/scalar");

match state.horizon_client.get(&scalar_url).send().await {
Ok(response) => {
// Extract content-type header before consuming the response
let content_type = response
.headers()
.get("content-type")
.unwrap_or(&HeaderValue::from_static("text/html"))
.clone();

match response.text().await {
Ok(res_text) => Response::builder()
.header("content-type", content_type)
.body(Body::from(res_text))
.unwrap(),
Err(_) => {
(StatusCode::INTERNAL_SERVER_ERROR, "Failed to read response").into_response()
}
}
}
Err(_) => (
StatusCode::SERVICE_UNAVAILABLE,
"Horizon service unavailable",
)
.into_response(),
}
}

/// Creates a router for OpenAPI documentation routes
pub(crate) fn router() -> Router<AppState> {
Router::new()
.route("/openapi.json", get(openapi_json_handler))
.route("/redoc", get(redoc_handler))
.route("/scalar", get(scalar_handler))
}
Loading