snap_control/api/http.rs
1// Copyright 2026 Anapaya Systems
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//! HTTP API endpoint definitions and endpoint handlers.
15
16use std::sync::Arc;
17
18use axum::{Json, routing::get};
19use utoipa::OpenApi;
20use utoipa_axum::router::OpenApiRouter;
21
22use crate::api::http::model::PgWapSessionManager;
23
24mod v1;
25
26#[derive(OpenApi)]
27#[openapi(info(
28 title = "SNAP HTTP API",
29 version = "0.1.0",
30 description = "Anapaya SNAP HTTP API"
31))]
32struct SnapApi;
33
34/// HTTP API models.
35pub mod model {
36 use std::net::IpAddr;
37
38 /// Information about an authenticated IP address.
39 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
40 pub struct Session {
41 /// The authenticated IP address.
42 pub ip: IpAddr,
43 /// The AP ID to use for sessions authenticated with this IP address.
44 pub ap_id: String,
45 /// The port to use for data plane sessions.
46 pub data_plane_port: u16,
47 /// The time until which the authentication is valid. After this time, the client needs to
48 /// reauthenticate.
49 pub valid_until: chrono::DateTime<chrono::Utc>,
50 /// The target domains a client is allowed to connect to.
51 pub target_domains: Vec<String>,
52 }
53
54 /// PathGuard WAP session manager.
55 pub trait PgWapSessionManager: Send + Sync {
56 /// Create a new session for the given client IP address.
57 fn new_session(
58 &self,
59 client_ip: IpAddr,
60 target_domains: &[&str],
61 ) -> Result<Session, anyhow::Error>;
62 }
63}
64
65/// Nests the SNAP HTTP API routes into the provided `base_router`.
66pub fn nest_http_api(
67 router: axum::Router,
68 pg_wap_session_manager: Arc<dyn PgWapSessionManager>,
69) -> axum::Router {
70 let mut doc = SnapApi::openapi();
71
72 let (api_router, api_spec) = OpenApiRouter::new()
73 .nest(v1::PG_WAP_API_V1, v1::pg_wap_router(pg_wap_session_manager))
74 .split_for_parts();
75
76 doc.merge(api_spec);
77
78 router
79 .merge(api_router)
80 .route("/.well-known/openapi.json", get(|| async { Json(doc) }))
81}