aboutsummaryrefslogtreecommitdiffstats
path: root/src/server/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/mod.rs')
-rw-r--r--src/server/mod.rs125
1 files changed, 120 insertions, 5 deletions
diff --git a/src/server/mod.rs b/src/server/mod.rs
index 803135f..3301035 100644
--- a/src/server/mod.rs
+++ b/src/server/mod.rs
@@ -1,10 +1,125 @@
-use axum::Router;
-
-use crate::{config::Config, server::state::AppState};
-
+pub mod driver;
+pub mod error;
+mod middleware;
+pub mod routes;
pub mod shutdown;
pub mod state;
+use std::time::Duration;
+
+use activitypub_federation::config::{FederationConfig, FederationMiddleware};
+use axum::{
+ Router,
+ http::{HeaderName, StatusCode},
+};
+use tower_http::{
+ cors::{self, CorsLayer},
+ request_id::PropagateRequestIdLayer,
+ timeout::TimeoutLayer,
+ trace::TraceLayer,
+};
+use tracing::{error, info_span};
+use utoipa::OpenApi;
+use utoipa_axum::router::OpenApiRouter;
+
+use crate::{
+ config::Config,
+ server::{
+ middleware::request_id::{REQUEST_ID_HEADER, add_request_id},
+ routes::auth::OAuthDoc,
+ state::{AppState, federation},
+ },
+};
+
+#[derive(OpenApi)]
+#[openapi(
+ tags(
+ (name = routes::HEALTH, description = "Check API health"),
+ ),
+)]
+pub struct ApiDoc;
+
pub async fn router(config: &Config, state: AppState) -> anyhow::Result<Router<()>> {
- todo!()
+ let state = federation::add_federation(state, config).await?;
+
+ let mut doc = ApiDoc::openapi();
+ doc.merge(OAuthDoc::openapi());
+
+ let (router, _api) = OpenApiRouter::with_openapi(doc)
+ .routes(utoipa_axum::routes!(routes::health_check))
+ .routes(utoipa_axum::routes!(routes::auth::auth))
+ .split_for_parts();
+
+ #[cfg(feature = "swagger")]
+ let router = router.merge(
+ utoipa_swagger_ui::SwaggerUi::new("/swagger-ui")
+ .url("/api-docs/swaggerdoc.json", _api.clone()),
+ );
+
+ #[cfg(feature = "redoc")]
+ let router = {
+ use utoipa_redoc::Servable as _;
+ router.merge(utoipa_redoc::Redoc::with_url("/redoc", _api.clone()))
+ };
+
+ #[cfg(feature = "scalar")]
+ let router = {
+ use utoipa_scalar::Servable as _;
+ router.merge(utoipa_scalar::Scalar::with_url("/scalar", _api.clone()))
+ };
+
+ #[cfg(feature = "rapidoc")]
+ let router = router.merge(
+ utoipa_rapidoc::RapiDoc::with_openapi("/api-docs/rapidoc.json", _api).path("/rapidoc"),
+ );
+
+ let router = router
+ .layer(
+ TraceLayer::new_for_http().make_span_with(|request: &axum::http::Request<_>| {
+ if let Some(request_id) = request.headers().get(REQUEST_ID_HEADER) {
+ info_span!(
+ "http_request",
+ request_id = ?request_id,
+ )
+ } else {
+ error!("could not extract request_id");
+ info_span!("http_request")
+ }
+ }),
+ )
+ .layer(TimeoutLayer::with_status_code(
+ StatusCode::REQUEST_TIMEOUT,
+ Duration::from_secs(config.server.request_timeout),
+ ))
+ .layer(FederationMiddleware::new(state))
+ // send headers from request to response headers
+ .layer(PropagateRequestIdLayer::new(HeaderName::from_static(
+ REQUEST_ID_HEADER,
+ )))
+ .layer(axum::middleware::from_fn(add_request_id))
+ .layer(
+ CorsLayer::new()
+ .allow_origin(cors::Any)
+ .allow_headers(cors::Any)
+ .allow_methods(cors::Any),
+ );
+
+ Ok(router)
+}
+
+#[cfg(test)]
+pub mod bootstrap {
+ use async_trait::async_trait;
+
+ use crate::server::driver::SellershutDriver;
+
+ #[derive(Debug, Default)]
+ pub struct TestDriver {}
+
+ #[async_trait]
+ impl SellershutDriver for TestDriver {
+ async fn hello(&self) {
+ todo!()
+ }
+ }
}