use axum::{Router, extract::State, response::IntoResponse, routing::get, serve};
use axum_reverse_proxy::ReverseProxy;
use serde_json::json;
use tokio::net::TcpListener;
use tracing::{Level, info};
use tracing_subscriber::FmtSubscriber;
#[derive(Clone)]
struct AppState {
app_name: String,
version: String,
}
#[tokio::main]
async fn main() {
FmtSubscriber::builder()
.with_max_level(Level::INFO)
.with_target(false)
.with_thread_ids(true)
.with_file(true)
.with_line_number(true)
.compact()
.init();
let state = AppState {
app_name: "My API Gateway".to_string(),
version: "1.0.0".to_string(),
};
let proxy = ReverseProxy::new("/api", "https://httpbin.org");
let app = Router::new()
.route("/", get(root_handler))
.with_state(state.clone());
let proxy_router: Router = proxy.into();
let app = app.merge(proxy_router);
let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap();
info!("Server running on http://localhost:3000");
info!("Try:");
info!(" - GET / -> App info");
info!(" - GET /api/ip -> Proxied to httpbin.org/ip");
info!(" - GET /api/uuid -> Proxied to httpbin.org/uuid");
serve(listener, app).await.unwrap();
}
async fn root_handler(State(state): State<AppState>) -> impl IntoResponse {
axum::Json(json!({
"app": state.app_name,
"version": state.version,
"endpoints": {
"/": "This info",
"/api/*": "Proxied to httpbin.org"
}
}))
}