Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add command to generate OpenAPI 3.0 Specs from exisiting json-rpc endpoint documentation #3802

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ futures = "0.3.19"
serde_json = "1"
log = "0.4"
term = "0.6"
serde_yaml = "0.9"
syn = { version = "2.0", features = ["full", "parsing"] }

grin_api = { path = "./api", version = "5.4.0-alpha.0" }
grin_config = { path = "./config", version = "5.4.0-alpha.0" }
Expand Down
98 changes: 98 additions & 0 deletions api/src/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright 2021 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// Attribute macro for documenting API endpoints
///
/// Example usage:
/// ```rust
/// #[api_endpoint]
/// #[endpoint(
/// path = "/v1/status",
/// method = "GET",
/// summary = "Get node status",
/// description = "Returns the current status of the node"
/// )]
/// pub struct StatusHandler {
/// pub chain: Weak<Chain>,
/// }
/// ```
#[macro_export]
macro_rules! api_endpoint {
(
$(#[endpoint(
path = $path:expr,
method = $method:expr,
summary = $summary:expr,
description = $description:expr
$(, params = [$($param:expr),*])?
$(, response = $response:ty)?
)])*
pub struct $name:ident {
$($field:ident: $type:ty),* $(,)?
}
) => {
pub struct $name {
$($field: $type),*
}

impl ApiEndpoint for $name {
fn get_endpoint_spec() -> EndpointSpec {
EndpointSpec {
path: $path.to_string(),
method: $method.to_string(),
summary: $summary.to_string(),
description: $description.to_string(),
params: vec![$($($param.into()),*)?],
response: None $(Some(stringify!($response).to_string()))?
}
}
}
};
}

/// Trait for types that represent API endpoints
pub trait ApiEndpoint {
fn get_endpoint_spec() -> EndpointSpec;
}

/// Represents an OpenAPI endpoint specification
pub struct EndpointSpec {
pub path: String,
pub method: String,
pub summary: String,
pub description: String,
pub params: Vec<ParamSpec>,
pub response: Option<String>,
}

/// Represents an OpenAPI parameter specification
pub struct ParamSpec {
pub name: String,
pub description: String,
pub required: bool,
pub schema_type: String,
pub location: String,
}

impl From<(&str, &str, bool, &str, &str)> for ParamSpec {
fn from(tuple: (&str, &str, bool, &str, &str)) -> Self {
ParamSpec {
name: tuple.0.to_string(),
description: tuple.1.to_string(),
required: tuple.2,
schema_type: tuple.3.to_string(),
location: tuple.4.to_string(),
}
}
}
20 changes: 20 additions & 0 deletions src/bin/grin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ extern crate log;
use crate::config::config::SERVER_CONFIG_FILE_NAME;
use crate::core::global;
use crate::tools::check_seeds;
use crate::tools::openapi;
use crate::util::init_logger;
use clap::App;
use futures::channel::oneshot;
Expand Down Expand Up @@ -222,6 +223,25 @@ fn real_main() -> i32 {
0
}

// openapi command
("openapi", Some(args)) => {
let output = args.value_of("output").unwrap();
let format = args.value_of("format").unwrap();
match openapi::generate_openapi_spec(output, format) {
Ok(_) => {
println!(
"Successfully generated OpenAPI documentation at: {}",
output
);
0
}
Err(e) => {
error!("Failed to generate OpenAPI documentation: {}", e);
1
}
}
}

// If nothing is specified, try to just use the config file instead
// this could possibly become the way to configure most things
// with most command line options being phased out
Expand Down
15 changes: 15 additions & 0 deletions src/bin/grin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,18 @@ subcommands:
help: Output file to write the results to
long: output
takes_value: true
- openapi:
about: Generate OpenAPI documentation from JSON-RPC endpoints
args:
- output:
help: Output file path
short: o
long: output
takes_value: true
required: true
- format:
help: Output format (json or yaml)
short: f
long: format
takes_value: true
default_value: json
2 changes: 2 additions & 0 deletions src/bin/tools/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@
mod seedcheck;

pub use seedcheck::check_seeds;

pub mod openapi;
Loading
Loading