1use lenso_bootstrap::CompositionProfile;
9use platform_core::AppContext;
10use platform_http::{ApiOpenApiRouter, OpenApiRouter, base_router};
11use utoipa::OpenApi;
12
13#[derive(OpenApi)]
19#[openapi(
20 info(
21 title = "Lenso API",
22 version = "1.0.0",
23 description = "Rust-first modular monolith API contract"
24 ),
25 tags(
26 (name = "auth", description = "Auth module development session APIs"),
27 (name = "admin-runtime", description = "Read-only runtime console APIs"),
28 (name = "admin-config", description = "Editable configuration console APIs"),
29 (name = "admin-data", description = "Schema-driven admin data console APIs")
30 )
31)]
32struct ApiDoc;
33
34pub(crate) fn api_router() -> ApiOpenApiRouter {
41 api_router_for_profile(CompositionProfile::default())
42}
43
44pub(crate) fn api_router_for_profile(profile: CompositionProfile) -> ApiOpenApiRouter {
45 let base = OpenApiRouter::with_openapi(openapi_document_for_profile_with_composition(
46 profile,
47 &lenso_bootstrap::HostComposition::default(),
48 ))
49 .merge(base_router());
50 lenso_bootstrap::merge_linked_http_for_profile(base, profile)
51 .merge(platform_admin::router())
52 .merge(platform_admin_data::router())
53 .merge(platform_module_remote::router())
54}
55
56pub(crate) fn api_router_for_context_with_composition(
57 ctx: &AppContext,
58 composition: &lenso_bootstrap::HostComposition,
59) -> platform_core::AppResult<ApiOpenApiRouter> {
60 let profile = CompositionProfile::from_config(&ctx.config)?;
61 let base = OpenApiRouter::with_openapi(openapi_document_for_profile_with_composition(
62 profile,
63 composition,
64 ))
65 .merge(base_router());
66 Ok(
67 lenso_bootstrap::merge_linked_http_for_context_with_composition(base, ctx, composition)?
68 .merge(platform_admin::router())
69 .merge(platform_admin_data::router())
70 .merge(platform_module_remote::router()),
71 )
72}
73
74fn openapi_document_for_profile_with_composition(
75 profile: CompositionProfile,
76 composition: &lenso_bootstrap::HostComposition,
77) -> utoipa::openapi::OpenApi {
78 let mut document = ApiDoc::openapi();
79 if let Some(tags) = &mut document.tags {
80 let has_auth = profile == CompositionProfile::Demo
81 || composition
82 .linked_modules()
83 .iter()
84 .any(|module| module.module_name == "auth");
85 match profile {
86 CompositionProfile::Core => tags.retain(|tag| has_auth || tag.name != "auth"),
87 CompositionProfile::Demo => {}
88 }
89 }
90 document
91}
92
93#[must_use]
95pub fn openapi_document() -> utoipa::openapi::OpenApi {
96 api_router().to_openapi()
97}