Skip to content

Commit b0e2c4a

Browse files
authored
feat: catalyst-gateway docs generation cli command (#136)
* refactor * add Docs settings * finilize * fix fmt * fix * cleanup
1 parent 72ae62d commit b0e2c4a

File tree

6 files changed

+55
-28
lines changed

6 files changed

+55
-28
lines changed

catalyst-gateway/bin/src/cli.rs

+20-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
//! CLI interpreter for the service
2-
use std::sync::Arc;
2+
use std::{io::Write, sync::Arc};
33

44
use clap::Parser;
55

6-
use crate::{logger, service, settings::Settings, state::State};
6+
use crate::{
7+
logger, service,
8+
settings::{DocsSettings, ServiceSettings},
9+
state::State,
10+
};
711

812
#[derive(thiserror::Error, Debug)]
913
/// All service errors
@@ -21,7 +25,9 @@ pub(crate) enum Error {
2125
/// Simple service CLI options
2226
pub(crate) enum Cli {
2327
/// Run the service
24-
Run(Settings),
28+
Run(ServiceSettings),
29+
/// Build API docs of the service in the JSON format
30+
Docs(DocsSettings),
2531
}
2632

2733
impl Cli {
@@ -46,6 +52,17 @@ impl Cli {
4652
service::run(&settings.address, state).await?;
4753
Ok(())
4854
},
55+
Self::Docs(settings) => {
56+
let docs = service::get_app_docs();
57+
match settings.output {
58+
Some(path) => {
59+
let mut docs_file = std::fs::File::create(path)?;
60+
docs_file.write_all(docs.as_bytes())?;
61+
},
62+
None => println!("{docs}"),
63+
}
64+
Ok(())
65+
},
4966
}
5067
}
5168
}

catalyst-gateway/bin/src/logger.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,13 @@ impl From<LogLevel> for tracing::Level {
3333
}
3434
}
3535

36-
impl LogLevel {
37-
/// Map [`LogLevel`] to [`tracing::Level`]
38-
pub(crate) fn as_log_level(self) -> tracing::log::LevelFilter {
39-
match self {
40-
LogLevel::Info => tracing::log::LevelFilter::Info,
41-
LogLevel::Debug => tracing::log::LevelFilter::Debug,
42-
LogLevel::Warn => tracing::log::LevelFilter::Warn,
43-
LogLevel::Error => tracing::log::LevelFilter::Error,
36+
impl From<LogLevel> for tracing::log::LevelFilter {
37+
fn from(val: LogLevel) -> Self {
38+
match val {
39+
LogLevel::Debug => Self::Debug,
40+
LogLevel::Info => Self::Info,
41+
LogLevel::Warn => Self::Warn,
42+
LogLevel::Error => Self::Error,
4443
}
4544
}
4645
}
@@ -63,7 +62,7 @@ pub(crate) fn init(log_level: LogLevel) -> Result<(), SetGlobalDefaultError> {
6362
.finish();
6463

6564
// Logging is globally disabled by default, so globally enable it to the required level.
66-
tracing::log::set_max_level(log_level.as_log_level());
65+
tracing::log::set_max_level(log_level.into());
6766

6867
tracing::subscriber::set_global_default(subscriber)
6968
}

catalyst-gateway/bin/src/service/docs/mod.rs

+7-10
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,24 @@ use poem_openapi::{OpenApi, OpenApiService, Webhook};
55
use rust_embed::RustEmbed;
66

77
/// Create the documentation pages where the `OpenAPI` docs can be viewed.
8-
pub(crate) fn docs<T: OpenApi + 'static, W: Webhook + 'static>(
9-
api_service: &OpenApiService<T, W>,
10-
) -> Route {
11-
let spec = api_service.spec();
12-
8+
pub(crate) fn docs<T, W>(api_service: &OpenApiService<T, W>) -> Route
9+
where
10+
T: OpenApi + 'static,
11+
W: Webhook + 'static,
12+
{
1313
let swagger_ui = api_service.swagger_ui();
1414
let rapidoc_ui = api_service.rapidoc();
1515
let redoc_ui = api_service.redoc();
1616
let openapi_explorer = api_service.openapi_explorer();
17-
let stoplight_ui = stoplight_elements::create_endpoint(&spec);
17+
let stoplight_ui = stoplight_elements::create_endpoint(&api_service.spec());
1818

1919
Route::new()
2020
.at("/", get(stoplight_ui))
2121
.nest("/swagger_ui", swagger_ui)
2222
.nest("/redoc", redoc_ui)
2323
.nest("/rapidoc", rapidoc_ui)
2424
.nest("/openapi_explorer", openapi_explorer)
25-
.at(
26-
"/cat-gateway.json",
27-
poem::endpoint::make_sync(move |_| spec.clone()),
28-
)
25+
.at("/cat-gateway.json", api_service.spec_endpoint())
2926
}
3027

3128
/// Embed static files.

catalyst-gateway/bin/src/service/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ mod common;
1515
mod poem_service;
1616
mod utilities;
1717

18+
pub(crate) use poem_service::get_app_docs;
19+
1820
/// Service level errors
1921
#[derive(thiserror::Error, Debug)]
2022
pub(crate) enum Error {

catalyst-gateway/bin/src/service/poem_service.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@ use crate::{
3030
};
3131

3232
/// This exists to allow us to add extra routes to the service for testing purposes.
33-
pub(crate) fn mk_app(
34-
hosts: Vec<String>, base_route: Option<Route>, state: &Arc<State>,
35-
) -> impl Endpoint {
33+
fn mk_app(hosts: Vec<String>, base_route: Option<Route>, state: &Arc<State>) -> impl Endpoint {
3634
// Get the base route if defined, or a new route if not.
3735
let base_route = match base_route {
3836
Some(route) => route,
@@ -57,6 +55,12 @@ pub(crate) fn mk_app(
5755
.data(state.clone())
5856
}
5957

58+
/// Get the API docs as a string in the JSON format.
59+
pub(crate) fn get_app_docs() -> String {
60+
let api_service = mk_api(vec![]);
61+
api_service.spec()
62+
}
63+
6064
/// Run the Poem Service
6165
///
6266
/// This provides only the primary entrypoint to the service.

catalyst-gateway/bin/src/settings.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
use std::{
33
env,
44
net::{IpAddr, SocketAddr},
5+
path::PathBuf,
56
};
67

78
use clap::Args;
@@ -41,7 +42,7 @@ const API_URL_PREFIX_DEFAULT: &str = "/api";
4142
/// the URL to the `PostgreSQL` event database,
4243
/// and the logging level.
4344
#[derive(Args, Clone)]
44-
pub(crate) struct Settings {
45+
pub(crate) struct ServiceSettings {
4546
/// Server binding address
4647
#[clap(long, default_value = ADDRESS_DEFAULT)]
4748
pub(crate) address: SocketAddr,
@@ -55,6 +56,13 @@ pub(crate) struct Settings {
5556
pub(crate) log_level: LogLevel,
5657
}
5758

59+
/// Settings specifies `OpenAPI` docs generation.
60+
#[derive(Args, Clone)]
61+
pub(crate) struct DocsSettings {
62+
/// The output path to the generated docs file, if omitted prints to stdout.
63+
pub(crate) output: Option<PathBuf>,
64+
}
65+
5866
/// An environment variable read as a string.
5967
pub(crate) struct StringEnvVar(String);
6068

@@ -256,10 +264,10 @@ mod tests {
256264
// }
257265

258266
#[test]
259-
fn generate_github_issue_url() {
267+
fn generate_github_issue_url_test() {
260268
let title = "Hello, World! How are you?";
261269
assert_eq!(
262-
super::generate_github_issue_url(title).unwrap().as_str(),
270+
generate_github_issue_url(title).unwrap().as_str(),
263271
"https://github.com/input-output-hk/catalyst-core/issues/new?template=bug_report.md&title=Hello%2C+World%21+How+are+you%3F"
264272
);
265273
}

0 commit comments

Comments
 (0)