Skip to content

Commit 3bf6715

Browse files
author
Yeastplume
committed
first attempt at adding openapi generation from existing docs
1 parent b93d88b commit 3bf6715

File tree

7 files changed

+1026
-0
lines changed

7 files changed

+1026
-0
lines changed

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ futures = "0.3.19"
3333
serde_json = "1"
3434
log = "0.4"
3535
term = "0.6"
36+
serde_yaml = "0.9"
37+
syn = { version = "2.0", features = ["full", "parsing"] }
3638

3739
grin_api = { path = "./api", version = "5.4.0-alpha.0" }
3840
grin_config = { path = "./config", version = "5.4.0-alpha.0" }

api/src/macros.rs

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright 2021 The Grin Developers
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+
15+
/// Attribute macro for documenting API endpoints
16+
///
17+
/// Example usage:
18+
/// ```rust
19+
/// #[api_endpoint]
20+
/// #[endpoint(
21+
/// path = "/v1/status",
22+
/// method = "GET",
23+
/// summary = "Get node status",
24+
/// description = "Returns the current status of the node"
25+
/// )]
26+
/// pub struct StatusHandler {
27+
/// pub chain: Weak<Chain>,
28+
/// }
29+
/// ```
30+
#[macro_export]
31+
macro_rules! api_endpoint {
32+
(
33+
$(#[endpoint(
34+
path = $path:expr,
35+
method = $method:expr,
36+
summary = $summary:expr,
37+
description = $description:expr
38+
$(, params = [$($param:expr),*])?
39+
$(, response = $response:ty)?
40+
)])*
41+
pub struct $name:ident {
42+
$($field:ident: $type:ty),* $(,)?
43+
}
44+
) => {
45+
pub struct $name {
46+
$($field: $type),*
47+
}
48+
49+
impl ApiEndpoint for $name {
50+
fn get_endpoint_spec() -> EndpointSpec {
51+
EndpointSpec {
52+
path: $path.to_string(),
53+
method: $method.to_string(),
54+
summary: $summary.to_string(),
55+
description: $description.to_string(),
56+
params: vec![$($($param.into()),*)?],
57+
response: None $(Some(stringify!($response).to_string()))?
58+
}
59+
}
60+
}
61+
};
62+
}
63+
64+
/// Trait for types that represent API endpoints
65+
pub trait ApiEndpoint {
66+
fn get_endpoint_spec() -> EndpointSpec;
67+
}
68+
69+
/// Represents an OpenAPI endpoint specification
70+
pub struct EndpointSpec {
71+
pub path: String,
72+
pub method: String,
73+
pub summary: String,
74+
pub description: String,
75+
pub params: Vec<ParamSpec>,
76+
pub response: Option<String>,
77+
}
78+
79+
/// Represents an OpenAPI parameter specification
80+
pub struct ParamSpec {
81+
pub name: String,
82+
pub description: String,
83+
pub required: bool,
84+
pub schema_type: String,
85+
pub location: String,
86+
}
87+
88+
impl From<(&str, &str, bool, &str, &str)> for ParamSpec {
89+
fn from(tuple: (&str, &str, bool, &str, &str)) -> Self {
90+
ParamSpec {
91+
name: tuple.0.to_string(),
92+
description: tuple.1.to_string(),
93+
required: tuple.2,
94+
schema_type: tuple.3.to_string(),
95+
location: tuple.4.to_string(),
96+
}
97+
}
98+
}

src/bin/grin.rs

+20
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ extern crate log;
2222
use crate::config::config::SERVER_CONFIG_FILE_NAME;
2323
use crate::core::global;
2424
use crate::tools::check_seeds;
25+
use crate::tools::openapi;
2526
use crate::util::init_logger;
2627
use clap::App;
2728
use futures::channel::oneshot;
@@ -222,6 +223,25 @@ fn real_main() -> i32 {
222223
0
223224
}
224225

226+
// openapi command
227+
("openapi", Some(args)) => {
228+
let output = args.value_of("output").unwrap();
229+
let format = args.value_of("format").unwrap();
230+
match openapi::generate_openapi_spec(output, format) {
231+
Ok(_) => {
232+
println!(
233+
"Successfully generated OpenAPI documentation at: {}",
234+
output
235+
);
236+
0
237+
}
238+
Err(e) => {
239+
error!("Failed to generate OpenAPI documentation: {}", e);
240+
1
241+
}
242+
}
243+
}
244+
225245
// If nothing is specified, try to just use the config file instead
226246
// this could possibly become the way to configure most things
227247
// with most command line options being phased out

src/bin/grin.yml

+15
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,18 @@ subcommands:
103103
help: Output file to write the results to
104104
long: output
105105
takes_value: true
106+
- openapi:
107+
about: Generate OpenAPI documentation from JSON-RPC endpoints
108+
args:
109+
- output:
110+
help: Output file path
111+
short: o
112+
long: output
113+
takes_value: true
114+
required: true
115+
- format:
116+
help: Output format (json or yaml)
117+
short: f
118+
long: format
119+
takes_value: true
120+
default_value: json

src/bin/tools/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@
1616
mod seedcheck;
1717

1818
pub use seedcheck::check_seeds;
19+
20+
pub mod openapi;

0 commit comments

Comments
 (0)