Skip to content

[OpenAPI] Merge multiple paths in a single operation #4415

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

Merged
merged 5 commits into from
Jun 9, 2025
Merged
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
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ transform-to-openapi: ## Generate the OpenAPI definition from the compiled schem
@npm run transform-to-openapi -- --schema output/schema/schema.json --flavor stack --output output/openapi/elasticsearch-openapi.json
@npm run transform-to-openapi -- --schema output/schema/schema.json --flavor serverless --output output/openapi/elasticsearch-serverless-openapi.json

transform-to-openapi-for-docs: ## Generate the OpenAPI definition tailored for API docs generation
@npm run transform-to-openapi -- --schema output/schema/schema.json --flavor stack --lift-enum-descriptions --merge-multipath-endpoints --output output/openapi/elasticsearch-openapi-docs.json

filter-for-serverless: ## Generate the serverless version from the compiled schema
@npm run --prefix compiler filter-by-availability -- --serverless --visibility=public --input ../output/schema/schema.json --output ../output/output/openapi/elasticsearch-serverless-openapi.json

Expand Down
23 changes: 14 additions & 9 deletions compiler-rs/clients_schema_to_openapi/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@ pub struct Cli {
#[argh(option, default = "SchemaFlavor::All")]
pub flavor: SchemaFlavor,

/// add enum descriptions to property descriptions [default = true]
#[argh(option, default = "true")]
pub lift_enum_descriptions: bool,

/// generate only this namespace (can be repeated)
#[argh(option)]
pub namespace: Vec<String>,

/// add enum descriptions to property descriptions [default = true]
#[argh(switch)]
pub lift_enum_descriptions: bool,

/// merge endpoints with multiple paths into a single OpenAPI operation [default = false]
#[argh(switch)]
pub merge_multipath_endpoints: bool,
}

use derive_more::FromStr;
Expand All @@ -42,20 +46,21 @@ pub enum SchemaFlavor {
}

impl From<Cli> for Configuration {
fn from(val: Cli) -> Configuration {
let flavor = match val.flavor {
fn from(cli: Cli) -> Configuration {
let flavor = match cli.flavor {
SchemaFlavor::All => None,
SchemaFlavor::Serverless => Some(Flavor::Serverless),
SchemaFlavor::Stack => Some(Flavor::Stack),
};

Configuration {
flavor,
lift_enum_descriptions: val.lift_enum_descriptions,
namespaces: if val.namespace.is_empty() {
lift_enum_descriptions: cli.lift_enum_descriptions,
merge_multipath_endpoints: cli.merge_multipath_endpoints,
namespaces: if cli.namespace.is_empty() {
None
} else {
Some(val.namespace)
Some(cli.namespace)
},
}
}
Expand Down
8 changes: 8 additions & 0 deletions compiler-rs/clients_schema_to_openapi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,15 @@ use crate::components::TypesAndComponents;
pub struct Configuration {
pub flavor: Option<Flavor>,
pub namespaces: Option<Vec<String>>,

/// If a property value is an enumeration, the description of possible values will be copied in the
/// property's description (also works for arrays of enums).
pub lift_enum_descriptions: bool,

/// Will output endpoints having multiple paths into a single operation. The operation's path will
/// be the longest one (with values for all optional parameters), and the other paths will be added
/// at the beginning of the operation's description.
pub merge_multipath_endpoints: bool,
}

/// Convert an API model into an OpenAPI v3 schema, optionally filtered for a given flavor
Expand Down
61 changes: 61 additions & 0 deletions compiler-rs/clients_schema_to_openapi/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,67 @@ pub fn add_endpoint(
// TODO: add error responses
};

//---- Merge multipath endpoints if asked for
let mut new_endpoint: clients_schema::Endpoint;

let endpoint = if is_multipath && tac.config.merge_multipath_endpoints {
new_endpoint = endpoint.clone();
let endpoint = &mut new_endpoint;

// Sort paths from smallest to longest
endpoint.urls.sort_by_key(|x| x.path.len());

// Keep the longest and its last method so that the operation's path+method are the same as the last one
// (avoids the perception that it may have been chosen randomly).
let mut longest_path = endpoint.urls.last().unwrap().clone();
while longest_path.methods.len() > 1 {
longest_path.methods.remove(0);
}

// Replace endpoint urls with the longest path
let mut urls = vec![longest_path];
std::mem::swap(&mut endpoint.urls, &mut urls);

let split_desc = split_summary_desc(&endpoint.description);

// Make sure the description is stays at the top
let mut description = match split_desc.summary {
Some(summary) => format!("{summary}\n\n"),
None => String::new(),
};

// Convert removed paths to descriptions
write!(description, "**All methods and paths for this operation:**\n\n")?;

for url in urls {
for method in url.methods {
let lower_method = method.to_lowercase();
let path = &url.path;
write!(
description,
r#"<div>
<span class="operation-verb {lower_method}">{method}</span>
<span class="operation-path">{path}</span>
</div>
"#
)?;
}
}

if let Some(desc) = &split_desc.description {
write!(description, "\n\n{}", desc)?;
}

// Replace description
endpoint.description = description;

// Done
endpoint
} else {
// Not multipath or not asked to merge multipath
endpoint
};

//---- Build a path for each url + method
let mut operation_counter = 0;

Expand Down
Binary file modified compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib_bg.wasm
Binary file not shown.
Loading
Loading