Skip to content

Commit 9387bf7

Browse files
lcawlswallez
andauthored
Output a redirect map when merging multipath operations (#4545) (#4588)
(cherry picked from commit 6132f6c) Co-authored-by: Sylvain Wallez <sylvain@elastic.co>
1 parent 6ce110b commit 9387bf7

File tree

10 files changed

+142
-58
lines changed

10 files changed

+142
-58
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ transform-to-openapi: ## Generate the OpenAPI definition from the compiled schem
5353
@npm run transform-to-openapi -- --schema output/schema/schema.json --flavor serverless --output output/openapi/elasticsearch-serverless-openapi.json
5454

5555
transform-to-openapi-for-docs: ## Generate the OpenAPI definition tailored for API docs generation
56-
@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
56+
@npm run transform-to-openapi -- --schema output/schema/schema.json --flavor stack --lift-enum-descriptions --merge-multipath-endpoints --multipath-redirects --output output/openapi/elasticsearch-openapi-docs.json
5757

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

compiler-rs/clients_schema_to_openapi/src/cli.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,22 @@ pub struct Cli {
3131
/// merge endpoints with multiple paths into a single OpenAPI operation [default = false]
3232
#[argh(switch)]
3333
pub merge_multipath_endpoints: bool,
34+
35+
/// output a redirection map when merging multipath endpoints
36+
#[argh(switch)]
37+
pub multipath_redirects: bool,
38+
}
39+
40+
impl Cli {
41+
pub fn redirect_path(&self, output: &PathBuf) -> Option<String> {
42+
if self.multipath_redirects {
43+
let path = output.to_string_lossy();
44+
let path = path.rsplit_once('.').unwrap().0;
45+
Some(format!("{}.redirects.csv", path))
46+
} else {
47+
None
48+
}
49+
}
3450
}
3551

3652
use derive_more::FromStr;
@@ -57,6 +73,7 @@ impl From<Cli> for Configuration {
5773
flavor,
5874
lift_enum_descriptions: cli.lift_enum_descriptions,
5975
merge_multipath_endpoints: cli.merge_multipath_endpoints,
76+
multipath_redirects: cli.multipath_redirects,
6077
namespaces: if cli.namespace.is_empty() {
6178
None
6279
} else {

compiler-rs/clients_schema_to_openapi/src/components.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18+
use std::collections::BTreeMap;
1819
use clients_schema::TypeName;
1920
use openapiv3::{Components, Parameter, ReferenceOr, RequestBody, Response, Schema, StatusCode};
2021
use crate::Configuration;
@@ -32,11 +33,19 @@ pub struct TypesAndComponents<'a> {
3233
pub config: &'a Configuration,
3334
pub model: &'a clients_schema::IndexedModel,
3435
pub components: &'a mut Components,
36+
// Redirections (if paths multipaths endpoints are merged)
37+
pub redirects: Option<BTreeMap<String, String>>,
3538
}
3639

3740
impl<'a> TypesAndComponents<'a> {
3841
pub fn new(config: &'a Configuration, model: &'a clients_schema::IndexedModel, components: &'a mut Components) -> TypesAndComponents<'a> {
39-
TypesAndComponents { config, model, components }
42+
let redirects = if config.merge_multipath_endpoints && config.multipath_redirects {
43+
Some(BTreeMap::new())
44+
} else {
45+
None
46+
};
47+
48+
TypesAndComponents { config, model, components, redirects }
4049
}
4150

4251
pub fn add_request_body(&mut self, endpoint: &str, body: RequestBody) -> ReferenceOr<RequestBody> {

compiler-rs/clients_schema_to_openapi/src/lib.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,18 @@ pub struct Configuration {
4141
/// be the longest one (with values for all optional parameters), and the other paths will be added
4242
/// at the beginning of the operation's description.
4343
pub merge_multipath_endpoints: bool,
44+
45+
/// Should we output a redirect map when merging multipath endpoints?
46+
pub multipath_redirects: bool,
47+
}
48+
49+
pub struct OpenApiConversion {
50+
pub openapi: OpenAPI,
51+
pub redirects: Option<String>,
4452
}
4553

4654
/// Convert an API model into an OpenAPI v3 schema, optionally filtered for a given flavor
47-
pub fn convert_schema(mut schema: IndexedModel, config: Configuration) -> anyhow::Result<OpenAPI> {
55+
pub fn convert_schema(mut schema: IndexedModel, config: Configuration) -> anyhow::Result<OpenApiConversion> {
4856
// Expand generics
4957
schema = clients_schema::transform::expand_generics(schema, ExpandConfig::default())?;
5058

@@ -74,7 +82,7 @@ pub fn convert_schema(mut schema: IndexedModel, config: Configuration) -> anyhow
7482
/// Note: there are ways to represent [generics in JSON Schema], but its unlikely that tooling will understand it.
7583
///
7684
/// [generics in JSON Schema]: https://json-schema.org/blog/posts/dynamicref-and-generics
77-
pub fn convert_expanded_schema(model: &IndexedModel, config: &Configuration) -> anyhow::Result<OpenAPI> {
85+
pub fn convert_expanded_schema(model: &IndexedModel, config: &Configuration) -> anyhow::Result<OpenApiConversion> {
7886
let mut openapi = OpenAPI {
7987
openapi: "3.0.3".into(),
8088
info: info(model),
@@ -130,7 +138,21 @@ pub fn convert_expanded_schema(model: &IndexedModel, config: &Configuration) ->
130138
// comp.security_schemes.sort_keys();
131139
// }
132140

133-
Ok(openapi)
141+
let redirects = if let Some(redirects) = tac.redirects {
142+
use std::fmt::Write;
143+
let mut result = String::new();
144+
for (source, target) in redirects.iter() {
145+
writeln!(&mut result, "{},{}", source, target)?;
146+
}
147+
Some(result)
148+
} else {
149+
None
150+
};
151+
152+
Ok(OpenApiConversion {
153+
openapi,
154+
redirects,
155+
})
134156
}
135157

136158
fn info(model: &IndexedModel) -> openapiv3::Info {
@@ -183,7 +205,7 @@ pub fn convert_availabilities(availabilities: &Option<Availabilities>, flavor: &
183205
let exp_since = format!("Technical preview{since_str}");
184206
result.insert("x-state".to_string(), Value::String(exp_since));
185207
}
186-
Stability::Stable => {
208+
Stability::Stable => {
187209
let stable_since = format!("Generally available{since_str}");
188210
result.insert("x-state".to_string(), Value::String(stable_since));
189211
}

compiler-rs/clients_schema_to_openapi/src/main.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@ fn main() -> anyhow::Result<()> {
3434

3535
let schema = IndexedModel::from_reader(File::open(&cli.schema)?)?;
3636
let output = cli.output.clone();
37+
let redirect_path = cli.redirect_path(&cli.output);
3738
let openapi = clients_schema_to_openapi::convert_schema(schema, cli.into())?;
38-
serde_json::to_writer_pretty(File::create(&output)?, &openapi)?;
39+
serde_json::to_writer_pretty(File::create(&output)?, &openapi.openapi)?;
40+
41+
if let Some(redirects) = openapi.redirects {
42+
let path = redirect_path.unwrap();
43+
std::fs::write(path, &redirects)?;
44+
}
45+
3946
Ok(())
4047
}

compiler-rs/clients_schema_to_openapi/src/paths.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,27 @@ pub fn add_endpoint(
233233
};
234234

235235
//---- Merge multipath endpoints if asked for
236+
237+
let operation_id: String = endpoint
238+
.name
239+
.chars()
240+
.map(|x| match x {
241+
'_' | '.' => '-',
242+
_ => x,
243+
})
244+
.collect();
245+
236246
let mut new_endpoint: clients_schema::Endpoint;
237247

238248
let endpoint = if is_multipath && tac.config.merge_multipath_endpoints {
249+
250+
// Add redirects for operations that would have been generated otherwise
251+
if let Some(ref mut map) = &mut tac.redirects {
252+
for i in 1..endpoint.urls.len() {
253+
map.insert(format!("{operation_id}-{i}"), operation_id.clone());
254+
}
255+
}
256+
239257
new_endpoint = endpoint.clone();
240258
let endpoint = &mut new_endpoint;
241259

@@ -315,9 +333,9 @@ pub fn add_endpoint(
315333
parameters.append(&mut query_params.clone());
316334

317335
let sum_desc = split_summary_desc(&endpoint.description);
318-
336+
319337
let privilege_desc = add_privileges(&endpoint.privileges);
320-
338+
321339
let full_desc = match (sum_desc.description, privilege_desc) {
322340
(Some(a), Some(b)) => Some(a+ &b),
323341
(opt_a, opt_b) => opt_a.or(opt_b)
@@ -419,14 +437,7 @@ pub fn add_endpoint(
419437
};
420438

421439
let mut operation = operation.clone();
422-
let mut operation_id: String = endpoint
423-
.name
424-
.chars()
425-
.map(|x| match x {
426-
'_' | '.' => '-',
427-
_ => x,
428-
})
429-
.collect();
440+
let mut operation_id = operation_id.clone();
430441
if operation_counter != 0 {
431442
write!(&mut operation_id, "-{}", operation_counter)?;
432443
}

compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib.js

Lines changed: 49 additions & 35 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Binary file not shown.

compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib_bg.wasm.d.ts

Lines changed: 2 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler-rs/compiler-wasm-lib/src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,21 @@ pub fn convert0(cli: Cli, cwd: Option<String>) -> anyhow::Result<()> {
5959
Some(ref cwd) => PathBuf::from(cwd).join(&cli.output),
6060
None => cli.output.clone(),
6161
};
62+
let redirect_path = cli.redirect_path(&output);
6263

6364
let json = node_fs::read_file_sync_to_string(&input.to_string_lossy(), "utf8");
6465
let schema = IndexedModel::from_reader(json.as_bytes())?;
6566

6667
let openapi = clients_schema_to_openapi::convert_schema(schema, cli.into())?;
6768

68-
let result = serde_json::to_string_pretty(&openapi)?;
69+
let result = serde_json::to_string_pretty(&openapi.openapi)?;
6970
node_fs::write_file_sync(&output.to_string_lossy(), &result);
71+
72+
if let Some(redirects) = openapi.redirects {
73+
let path = redirect_path.unwrap();
74+
node_fs::write_file_sync(&path, &redirects);
75+
}
76+
7077
Ok(())
7178
}
7279

0 commit comments

Comments
 (0)