1use axum::Router;
7use axum::response::IntoResponse;
8use sokuto_core::gating::{
9 CandidateProbability, DecisionRoute, EscalationContext, GatingConfig, GatingMetadata,
10 SystemRoutingSummary,
11};
12use sokuto_core::schema::{
13 Answer, Criteria, Question, QuestionType, StateBatchRequest, StateBatchResponse,
14 SystemOneRequest, SystemOneResponse, Usage,
15};
16use utoipa::OpenApi;
17
18use crate::error::{ErrorDetail, ErrorResponse};
19use crate::handlers::ops::HealthStatusResponse;
20use crate::schema::dag::{
21 DagDefinitionDto, DagEscalationDetailDto, DagNodeDto, DagNodeTypeDto, DagRequest, DagResponse,
22 DagStepResultDto, DagUsageDto, NodeConditionDto, NodeConditionOpDto,
23};
24
25#[derive(OpenApi)]
27#[openapi(
28 paths(
29 crate::handlers::systemone::system_one_handler,
30 crate::handlers::state_batch::state_batch_handler,
31 crate::handlers::dag::dag_handler,
32 crate::handlers::ops::health_handler,
33 crate::handlers::ops::ready_handler,
34 crate::handlers::ops::metrics_handler,
35 ),
36 components(
37 schemas(
38 SystemOneRequest,
39 SystemOneResponse,
40 StateBatchRequest,
41 StateBatchResponse,
42 Question,
43 QuestionType,
44 Criteria,
45 Answer,
46 Usage,
47 DecisionRoute,
48 GatingConfig,
49 GatingMetadata,
50 CandidateProbability,
51 EscalationContext,
52 SystemRoutingSummary,
53 ErrorResponse,
54 ErrorDetail,
55 HealthStatusResponse,
56 DagRequest,
57 DagResponse,
58 DagDefinitionDto,
59 DagNodeDto,
60 DagNodeTypeDto,
61 NodeConditionDto,
62 NodeConditionOpDto,
63 DagStepResultDto,
64 DagEscalationDetailDto,
65 DagUsageDto,
66 )
67 ),
68 tags(
69 (name = "Inference", description = "TypeSafe AI Jev 互換の非自己回帰型判断推論 API"),
70 (name = "Operations", description = "ヘルスチェックおよび Prometheus 監視運用 API")
71 ),
72 info(
73 title = "Sokuto HTTP API",
74 version = "0.0.0",
75 description = "TypeSafe AI Jev 互換の非自己回帰型判断特化モデル向け超低遅延 REST API 仕様書。"
76 )
77)]
78pub struct ApiDoc;
79
80pub fn generate_openapi_spec() -> utoipa::openapi::OpenApi {
82 let mut spec = ApiDoc::openapi();
83 spec.info.version = env!("CARGO_PKG_VERSION").to_string();
84 spec
85}
86
87pub fn export_openapi_json() -> String {
89 generate_openapi_spec()
90 .to_pretty_json()
91 .expect("OpenAPI 仕様の JSON シリアライズに失敗しました。")
92}
93
94pub async fn openapi_json_handler() -> impl IntoResponse {
96 (
97 [("content-type", "application/json; charset=utf-8")],
98 export_openapi_json(),
99 )
100}
101
102pub fn mount_swagger_ui<S>(router: Router<S>) -> Router<S>
106where
107 S: Clone + Send + Sync + 'static,
108{
109 #[cfg(feature = "swagger")]
110 {
111 use utoipa_swagger_ui::SwaggerUi;
112 router.merge(
113 SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", generate_openapi_spec()),
114 )
115 }
116
117 #[cfg(not(feature = "swagger"))]
118 {
119 router.route(
120 "/api-docs/openapi.json",
121 axum::routing::get(openapi_json_handler),
122 )
123 }
124}