flagrant_api/
lib.rs

1use axum::{routing::{delete, get, post, put}, Router
2};
3use tower_http::compression::CompressionLayer;
4use tower_http::trace::TraceLayer;
5use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
6
7use crate::handlers::projects;
8use crate::handlers::{environments, features, variants};
9
10mod api;
11mod errors;
12mod extractors;
13mod handlers;
14
15pub fn init_tracing() {
16    tracing_subscriber::registry()
17        .with(
18            tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
19                // axum logs rejections from built-in extractors with the `axum::rejection`
20                // target, at `TRACE` level. `axum::rejection=trace` enables showing those events
21                "flagrant_api=debug,flagrant=debug,tower_http=debug,axum::rejection=trace".into()
22            }),
23        )
24        .with(tracing_subscriber::fmt::layer())
25        .init();
26}
27
28pub async fn start_api_server() -> anyhow::Result<()> {
29    let pool = flagrant::init().await?;
30    let app = Router::new()
31        // projects
32        .route("/projects/:project_id", get(projects::fetch))
33
34        // environments
35        .route("/projects/:project_id/envs", get(environments::list))
36        .route("/projects/:project_id/envs", post(environments::create))
37        .route("/projects/:project_id/envs/:env_id", get(environments::fetch))
38
39        // features
40        .route("/envs/:environment_id/features", get(features::list))
41        .route("/envs/:environment_id/features", post(features::create))
42        .route("/envs/:environment_id/features/:feature_id", get(features::fetch))
43        .route("/envs/:environment_id/features/:feature_id", put(features::update))
44        .route("/envs/:environment_id/features/:feature_id", delete(features::delete))
45
46        // variants
47        .route("/envs/:environment_id/features/:feature_id/variants", get(variants::list))
48        .route("/envs/:environment_id/features/:feature_id/variants", post(variants::create))
49        .route("/envs/:environment_id/variants/:variant_id", get(variants::fetch))
50        .route("/envs/:environment_id/variants/:variant_id", put(variants::update))
51        .route("/envs/:environment_id/variants/:variant_id", delete(variants::delete))
52
53        // public API
54        .nest("/api/v1",
55              Router::new()
56                .route("/envs/:environment_id/ident/:ident/features/:feature_name", get(api::get_feature)))
57
58        .with_state(pool)
59        .layer(CompressionLayer::new())
60        .layer(TraceLayer::new_for_http());
61
62
63    let listener = tokio::net::TcpListener::bind("127.0.0.1:3030")
64        .await
65        .unwrap();
66
67    tracing::info!("listening on {}", listener.local_addr().unwrap());
68    axum::serve(listener, app).await.unwrap();
69
70    Ok(())
71}