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

Generate OpenAPI schema for Elasticsearch Serverless #2047

Merged
merged 17 commits into from
Oct 23, 2023
Merged

Conversation

swallez
Copy link
Member

@swallez swallez commented Mar 29, 2023

This PR adds a converter from schema.json to OpenAPI for Elasticsearch serverless.

make contrib now produces the output/openapi/elasticsearch-serverless-openapi.json file.

This converter is written in Rust. To ensure a smooth integration with our existing tooling, the Rust code is compiled to WebAssembly with a JavaScript binding using wasm-pack that exploses the OpenAPI generation function.

As part of this, the clients-schema crate provides a complete implementation of the schema.json metamodel along with utilities and common transformation functions such as generics expansion and flavor (stack/serverless) filtering.

Copy link
Contributor

@sethmlarson sethmlarson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is excellent, nice work @swallez! Left a few comments inline, some may not make sense due to unfamiliarity with Rust and this code:

openapi-converter/openapi_to_clients_schema/src/openapi.rs Outdated Show resolved Hide resolved
openapi-converter/openapi_to_clients_schema/src/openapi.rs Outdated Show resolved Hide resolved
openapi-converter/openapi_to_clients_schema/src/openapi.rs Outdated Show resolved Hide resolved
openapi-converter/openapi_to_clients_schema/src/types.rs Outdated Show resolved Hide resolved
openapi-converter/openapi_to_clients_schema/src/types.rs Outdated Show resolved Hide resolved
@github-actions
Copy link
Contributor

github-actions bot commented Jul 5, 2023

Following you can find the validation results for the APIs you have changed.

API Status Request Response
async_search.delete 🟢 3/3 3/3
async_search.get 🟢 4/4 4/4
async_search.status 🟢 3/3 3/3
async_search.submit 🟢 6/6 6/6
autoscaling.delete_autoscaling_policy Missing test Missing test
autoscaling.get_autoscaling_capacity Missing test Missing test
autoscaling.get_autoscaling_policy Missing test Missing test
autoscaling.put_autoscaling_policy Missing test Missing test
bulk 🟢 258/258 276/276
cat.aliases 🟢 24/24 24/24
cat.allocation 🟢 11/11 11/11
cat.component_templates Missing test Missing test
cat.count 🟢 9/9 9/9
cat.fielddata 🟢 6/6 6/6
cat.health 🟢 5/5 5/5
cat.help Missing test Missing test
cat.indices 🟢 32/32 31/31
cat.master 🟢 1/1 1/1
cat.ml_data_frame_analytics 🟢 5/5 5/5
cat.ml_datafeeds 🟢 4/4 4/4
cat.ml_jobs 🟢 4/4 4/4
cat.ml_trained_models 🟢 5/5 5/5
cat.nodeattrs 🟢 5/5 5/5
cat.nodes 🟢 11/11 11/11
cat.pending_tasks 🟢 1/1 1/1
cat.plugins 🟢 2/2 2/2
cat.recovery 🟢 6/6 6/6
cat.repositories 🟢 6/6 6/6
cat.segments 🟢 8/8 8/8
cat.shards 🟢 9/9 9/9
cat.snapshots 🟢 4/4 4/4
cat.tasks 🟢 11/11 11/11
cat.templates 🟢 14/14 14/14
cat.thread_pool 🟢 9/9 9/9
cat.transforms 🟢 5/5 5/5
ccr.delete_auto_follow_pattern Missing test Missing test
ccr.follow_info Missing test Missing test
ccr.follow_stats Missing test Missing test
ccr.follow Missing test Missing test
ccr.forget_follower Missing test Missing test
ccr.get_auto_follow_pattern Missing test Missing test
ccr.pause_auto_follow_pattern Missing test Missing test
ccr.pause_follow Missing test Missing test
ccr.put_auto_follow_pattern Missing test Missing test
ccr.resume_auto_follow_pattern Missing test Missing test
ccr.resume_follow Missing test Missing test
ccr.stats Missing test Missing test
ccr.unfollow Missing test Missing test
clear_scroll 🟢 17/17 17/17
close_point_in_time 🟢 10/10 10/10
cluster.allocation_explain 🟢 4/4 4/4
cluster.delete_component_template 🟢 2/2 2/2
cluster.delete_voting_config_exclusions 🟢 1/1 1/1
cluster.exists_component_template Missing test Missing test
cluster.get_component_template 🟢 8/8 8/8
cluster.get_settings 🟢 7/7 7/7
cluster.health 🟢 137/137 137/137
cluster.info Missing test Missing test
cluster.pending_tasks 🟢 3/3 3/3
cluster.post_voting_config_exclusions 🔴 5/5 1/5
cluster.put_component_template 🔴 12/14 14/14
cluster.put_settings 🟢 27/27 26/26
cluster.remote_info 🟢 3/3 3/3
cluster.reroute 🟢 6/6 5/5
cluster.state 🟢 52/52 51/51
cluster.stats 🟢 8/8 8/8
count 🟢 30/30 30/30
create 🟢 24/24 23/23
dangling_indices.delete_dangling_index Missing test Missing test
dangling_indices.import_dangling_index Missing test Missing test
dangling_indices.list_dangling_indices Missing test Missing test
delete_by_query_rethrottle 🟢 1/1 1/1
delete_by_query 🟢 5/5 4/4
delete_script 🟢 8/8 8/8
delete 🟢 34/34 34/34
enrich.delete_policy 🟢 5/5 5/5
enrich.execute_policy 🟢 6/6 6/6
enrich.get_policy 🟢 6/6 6/6
enrich.put_policy 🟢 6/6 6/6
enrich.stats 🟢 5/5 5/5
eql.delete 🟢 3/3 3/3
eql.get_status 🟢 3/3 3/3
eql.get 🟢 2/2 2/2
eql.search 🟢 24/24 24/24
exists_source 🟢 3/3 3/3
exists 🟢 19/19 19/19
explain 🟢 14/14 14/14
features.get_features 🟢 2/2 2/2
features.reset_features Missing test Missing test
field_caps 🟢 34/34 34/34
fleet.global_checkpoints Missing test Missing test
fleet.msearch Missing test Missing test
fleet.search Missing test Missing test
get_script_context 🟢 1/1 1/1
get_script_languages 🟢 1/1 1/1
get_script 🟢 12/12 12/12
get_source 🟢 18/18 18/18
get 🟢 94/94 91/91
graph.explore 🟢 4/4 4/4
health_report Missing test Missing test
ilm.delete_lifecycle 🟢 2/2 2/2
ilm.explain_lifecycle 🟢 5/5 5/5
ilm.get_lifecycle 🟢 8/8 8/8
ilm.get_status 🟢 4/4 4/4
ilm.migrate_to_data_tiers Missing test Missing test
ilm.move_to_step Missing test Missing test
ilm.put_lifecycle 🟢 6/6 6/6
ilm.remove_policy 🟢 5/5 5/5
ilm.retry Missing test Missing test
ilm.start Missing test Missing test
ilm.stop 🟢 4/4 4/4
index 🟢 677/677 679/679
indices.add_block 🟢 2/2 2/2
indices.analyze 🟢 20/20 20/20
indices.clear_cache 🟢 4/4 4/4
indices.clone 🟢 6/6 6/6
indices.close 🟢 42/42 42/42
indices.create_data_stream 🟢 25/25 25/25
indices.create 🔴 673/679 679/679
indices.data_streams_stats 🟢 4/4 4/4
indices.delete_alias 🟢 15/15 15/15
indices.delete_data_lifecycle Missing test Missing test
indices.delete_data_stream 🟢 27/27 27/27
indices.delete_index_template 🟢 1/1 1/1
indices.delete_template 🟢 9/9 9/9
indices.delete 🟢 104/104 104/104
indices.disk_usage 🟢 1/1 1/1
indices.downsample Missing test Missing test
indices.exists_alias 🟢 36/36 36/36
indices.exists_index_template Missing test Missing test
indices.exists_template 🟢 15/15 15/15
indices.exists 🟢 39/39 39/39
indices.explain_data_lifecycle Missing test Missing test
indices.field_usage_stats 🟢 5/5 5/5
indices.flush 🟢 9/9 9/9
indices.forcemerge 🔴 4/4 3/4
indices.get_alias 🔴 80/80 68/80
indices.get_data_lifecycle Missing test Missing test
indices.get_data_stream 🟢 12/12 12/12
indices.get_field_mapping 🔴 15/15 14/15
indices.get_index_template 🔴 16/16 14/16
indices.get_mapping 🟢 74/74 74/74
indices.get_settings 🔴 54/54 50/54
indices.get_template 🟢 30/30 30/30
indices.get 🟢 52/52 52/52
indices.migrate_to_data_stream Missing test Missing test
indices.modify_data_stream Missing test Missing test
indices.open 🟢 17/17 17/17
indices.promote_data_stream Missing test Missing test
indices.put_alias 🟢 54/54 54/54
indices.put_data_lifecycle Missing test Missing test
indices.put_index_template 🔴 36/37 37/37
indices.put_mapping 🔴 70/71 71/71
indices.put_settings 🔴 46/48 48/48
indices.put_template 🔴 39/41 41/41
indices.recovery 🟢 11/11 11/11
indices.refresh 🟢 202/202 202/202
indices.reload_search_analyzers 🟢 2/2 2/2
indices.resolve_index 🟢 5/5 5/5
indices.rollover 🟢 14/14 14/14
indices.segments 🔴 6/6 5/6
indices.shard_stores 🔴 5/5 4/5
indices.shrink 🟢 5/5 5/5
indices.simulate_index_template 🟢 4/4 4/4
indices.simulate_template 🟢 4/4 4/4
indices.split 🟢 4/4 4/4
indices.stats 🟢 82/82 81/81
indices.unfreeze 🟢 1/1 1/1
indices.update_aliases 🟢 22/22 22/22
indices.validate_query 🟢 7/7 7/7
info 🟢 5/5 5/5
ingest.delete_pipeline 🟢 11/11 11/11
ingest.geo_ip_stats Missing test Missing test
ingest.get_pipeline 🟢 22/22 22/22
ingest.processor_grok 🟢 1/1 1/1
ingest.put_pipeline 🟢 30/30 30/30
ingest.simulate 🟢 4/4 4/4
knn_search 🟢 2/2 2/2
license.delete 🟢 3/3 3/3
license.get_basic_status 🟢 3/3 3/3
license.get_trial_status 🟢 3/3 3/3
license.get 🟢 6/6 6/6
license.post_start_basic 🟢 5/5 5/5
license.post_start_trial 🟢 2/2 2/2
license.post 🟢 1/1 1/1
logstash.delete_pipeline Missing test Missing test
logstash.get_pipeline Missing test Missing test
logstash.put_pipeline Missing test Missing test
mget 🟢 45/45 44/44
migration.deprecations 🟢 2/2 2/2
migration.get_feature_upgrade_status 🟢 2/2 2/2
migration.post_feature_upgrade Missing test Missing test
ml.clear_trained_model_deployment_cache Missing test Missing test
ml.close_job 🟢 62/62 61/61
ml.delete_calendar_event 🟢 4/4 4/4
ml.delete_calendar_job 🟢 3/3 3/3
ml.delete_calendar 🟢 5/5 5/5
ml.delete_data_frame_analytics 🟢 2/2 2/2
ml.delete_datafeed 🟢 3/3 3/3
ml.delete_expired_data 🟢 5/5 5/5
ml.delete_filter 🟢 27/27 27/27
ml.delete_forecast 🟢 3/3 3/3
ml.delete_job 🟢 47/47 47/47
ml.delete_model_snapshot 🟢 2/2 2/2
ml.delete_trained_model_alias 🟢 3/3 3/3
ml.delete_trained_model 🟢 3/3 3/3
ml.estimate_model_memory 🟢 16/16 16/16
ml.evaluate_data_frame 🟢 22/22 22/22
ml.explain_data_frame_analytics 🟢 7/7 7/7
ml.flush_job 🟢 15/15 15/15
ml.forecast 🟢 1/1 1/1
ml.get_buckets 🟢 14/14 14/14
ml.get_calendar_events 🟢 17/17 17/17
ml.get_calendars 🟢 17/17 17/17
ml.get_categories 🟢 12/12 12/12
ml.get_data_frame_analytics_stats 🟢 12/12 12/12
ml.get_data_frame_analytics 🟢 17/17 17/17
ml.get_datafeed_stats 🟢 27/27 27/27
ml.get_datafeeds 🟢 20/20 20/20
ml.get_filters 🟢 13/13 13/13
ml.get_influencers 🟢 11/11 11/11
ml.get_job_stats 🟢 31/31 31/31
ml.get_jobs 🟢 31/31 31/31
ml.get_memory_stats Missing test Missing test
ml.get_model_snapshot_upgrade_stats 🟢 3/3 3/3
ml.get_model_snapshots 🟢 18/18 18/18
ml.get_overall_buckets 🟢 16/16 15/15
ml.get_records 🟢 8/8 8/8
ml.get_trained_models_stats 🟢 12/12 12/12
ml.get_trained_models 🔴 21/27 27/27
ml.infer_trained_model Missing test Missing test
ml.info 🟢 10/10 10/10
ml.open_job 🟢 83/83 83/83
ml.post_calendar_events 🟢 21/21 21/21
ml.post_data 🔴 8/10 13/17
ml.preview_data_frame_analytics 🟢 3/3 3/3
ml.preview_datafeed 🔴 10/16 16/16
ml.put_calendar_job 🔴 11/12 12/12
ml.put_calendar 🟢 135/135 135/135
ml.put_data_frame_analytics 🟢 33/33 33/33
ml.put_datafeed 🔴 70/71 71/71
ml.put_filter 🟢 27/27 27/27
ml.put_job 🔴 218/226 224/224
ml.put_trained_model_alias 🟢 9/9 9/9
ml.put_trained_model_definition_part Missing test Missing test
ml.put_trained_model_vocabulary Missing test Missing test
ml.put_trained_model 🟢 5/5 5/5
ml.reset_job 🟢 2/2 2/2
ml.revert_model_snapshot 🟢 2/2 2/2
ml.set_upgrade_mode 🟢 6/6 6/6
ml.start_data_frame_analytics 🟢 1/1 1/1
ml.start_datafeed 🟢 24/24 24/24
ml.start_trained_model_deployment Missing test Missing test
ml.stop_data_frame_analytics 🟢 5/5 5/5
ml.stop_datafeed 🟢 17/17 17/17
ml.stop_trained_model_deployment Missing test Missing test
ml.update_data_frame_analytics 🟢 2/2 2/2
ml.update_datafeed 🟢 7/7 7/7
ml.update_filter 🟢 3/3 3/3
ml.update_job 🔴 4/5 5/5
ml.update_model_snapshot 🟢 3/3 3/3
ml.update_trained_model_deployment 🟠 Missing type Missing type
ml.upgrade_job_snapshot 🟢 3/3 3/3
ml.validate_detector 🟢 2/2 2/2
ml.validate 🟢 3/3 3/3
monitoring.bulk Missing test Missing test
msearch_template 🟢 1/1 1/1
msearch 🟢 17/17 16/16
mtermvectors 🟢 10/10 10/10
nodes.clear_repositories_metering_archive Missing test Missing test
nodes.get_repositories_metering_info Missing test Missing test
nodes.hot_threads 🔴 5/5 0/5
nodes.info 🔴 84/84 16/84
nodes.reload_secure_settings 🟢 2/2 2/2
nodes.stats 🟢 42/42 42/42
nodes.usage 🟢 1/1 1/1
open_point_in_time 🟢 10/10 10/10
ping 🟢 2/2 2/2
put_script 🟢 9/9 9/9
rank_eval Missing test Missing test
reindex_rethrottle 🟢 2/2 2/2
reindex 🟢 15/15 14/14
render_search_template 🟢 1/1 1/1
rollup.delete_job 🟢 3/3 3/3
rollup.get_jobs 🟢 11/11 11/11
rollup.get_rollup_caps 🟢 3/3 3/3
rollup.get_rollup_index_caps 🟢 7/7 7/7
rollup.put_job 🟢 23/23 23/23
rollup.rollup_search 🟢 18/18 18/18
rollup.start_job 🟢 8/8 8/8
rollup.stop_job 🟢 5/5 5/5
scripts_painless_execute 🟢 2/2 2/2
scroll 🟢 69/69 20/20
search_application.delete_behavioral_analytics Missing test Missing test
search_application.delete Missing test Missing test
search_application.get_behavioral_analytics Missing test Missing test
search_application.get Missing test Missing test
search_application.list Missing test Missing test
search_application.post_behavioral_analytics_event 🟠 Missing type Missing type
search_application.put_behavioral_analytics Missing test Missing test
search_application.put Missing test Missing test
search_application.render_query 🟠 Missing type Missing type
search_application.search Missing test Missing test
search_mvt 🔴 27/27 0/27
search_shards 🟢 8/8 8/8
search_template 🟢 2/2 1/1
search 🔴 1519/1538 1519/1520
searchable_snapshots.cache_stats Missing test Missing test
searchable_snapshots.clear_cache 🟢 1/1 1/1
searchable_snapshots.mount 🟢 3/3 3/3
searchable_snapshots.stats 🟢 1/1 1/1
security.activate_user_profile Missing test Missing test
security.authenticate 🟢 15/15 15/15
security.bulk_update_api_keys 🟠 Missing type Missing type
security.change_password 🟢 6/6 6/6
security.clear_api_key_cache 🟢 9/9 9/9
security.clear_cached_privileges 🟢 3/3 3/3
security.clear_cached_realms 🟢 1/1 1/1
security.clear_cached_roles 🟢 2/2 2/2
security.clear_cached_service_tokens 🟢 4/4 4/4
security.create_api_key 🟢 25/25 16/16
security.create_cross_cluster_api_key 🟠 Missing type Missing type
security.create_service_token 🟢 2/2 2/2
security.delete_privileges 🟢 6/6 6/6
security.delete_role_mapping 🟢 9/9 9/9
security.delete_role 🟢 8/8 8/8
security.delete_service_token Missing test Missing test
security.delete_user 🟢 9/9 9/9
security.disable_user_profile Missing test Missing test
security.disable_user 🟢 3/3 3/3
security.enable_user_profile Missing test Missing test
security.enable_user 🟢 4/4 4/4
security.enroll_kibana Missing test Missing test
security.enroll_node Missing test Missing test
security.get_api_key 🟢 14/14 14/14
security.get_builtin_privileges 🟢 2/2 2/2
security.get_privileges 🟢 12/12 12/12
security.get_role_mapping 🟢 18/18 18/18
security.get_role 🟢 20/20 20/20
security.get_service_accounts Missing test Missing test
security.get_service_credentials 🟢 1/1 1/1
security.get_token 🟢 21/21 20/20
security.get_user_privileges 🟢 7/7 7/7
security.get_user_profile Missing test Missing test
security.get_user 🟢 24/24 24/24
security.grant_api_key Missing test Missing test
security.has_privileges_user_profile Missing test Missing test
security.has_privileges 🟢 9/9 9/9
security.invalidate_api_key 🟢 10/10 10/10
security.invalidate_token 🟢 11/11 11/11
security.oidc_authenticate 🟠 Missing type Missing type
security.oidc_logout 🟠 Missing type Missing type
security.oidc_prepare_authentication 🟠 Missing type Missing type
security.put_privileges 🟢 10/10 10/10
security.put_role_mapping 🟢 11/11 11/11
security.put_role 🟢 26/26 25/25
security.put_user 🟢 39/39 38/38
security.query_api_keys 🟢 7/7 7/7
security.saml_authenticate Missing test Missing test
security.saml_complete_logout Missing test Missing test
security.saml_invalidate Missing test Missing test
security.saml_logout Missing test Missing test
security.saml_prepare_authentication Missing test Missing test
security.saml_service_provider_metadata Missing test Missing test
security.suggest_user_profiles Missing test Missing test
security.update_api_key Missing test Missing test
security.update_cross_cluster_api_key 🟠 Missing type Missing type
security.update_user_profile_data Missing test Missing test
shutdown.delete_node Missing test Missing test
shutdown.get_node Missing test Missing test
shutdown.put_node Missing test Missing test
slm.delete_lifecycle 🟢 4/4 4/4
slm.execute_lifecycle 🟢 4/4 4/4
slm.execute_retention 🟢 4/4 4/4
slm.get_lifecycle 🟢 16/16 16/16
slm.get_stats 🟢 4/4 4/4
slm.get_status 🟢 4/4 4/4
slm.put_lifecycle 🟢 4/4 4/4
slm.start Missing test Missing test
slm.stop 🟢 4/4 4/4
snapshot.cleanup_repository 🟢 3/3 3/3
snapshot.clone 🟢 5/5 5/5
snapshot.create_repository 🟢 26/26 26/26
snapshot.create 🟢 25/25 25/25
snapshot.delete_repository 🟢 10/10 10/10
snapshot.delete 🟢 19/19 19/19
snapshot.get_repository 🟢 19/19 19/19
snapshot.get 🟢 12/12 12/12
snapshot.repository_analyze 🟠 Missing type Missing type
snapshot.restore 🟢 5/5 5/5
snapshot.status 🟢 2/2 2/2
snapshot.verify_repository 🟢 2/2 2/2
sql.clear_cursor 🟢 1/1 1/1
sql.delete_async Missing test Missing test
sql.get_async_status Missing test Missing test
sql.get_async Missing test Missing test
sql.query 🟢 5/5 5/5
sql.translate 🟢 1/1 1/1
ssl.certificates 🟢 2/2 2/2
tasks.cancel 🟢 2/2 2/2
tasks.get 🟢 10/10 10/10
tasks.list 🟢 8/8 8/8
terms_enum 🟢 27/27 27/27
termvectors 🟢 7/7 7/7
text_structure.find_structure 🟢 2/2 2/2
transform.delete_transform 🟢 9/9 9/9
transform.get_transform_stats 🟢 31/31 31/31
transform.get_transform 🟢 26/26 26/26
transform.preview_transform 🟢 16/16 16/16
transform.put_transform 🟢 24/24 24/24
transform.reset_transform 🟢 4/4 4/4
transform.schedule_now_transform Missing test Missing test
transform.start_transform 🟢 24/24 24/24
transform.stop_transform 🟢 15/15 15/15
transform.update_transform 🟢 13/13 13/13
transform.upgrade_transforms 🟢 2/2 2/2
update_by_query_rethrottle 🟢 1/1 1/1
update_by_query 🟢 5/5 4/4
update 🟢 33/33 33/33
watcher.ack_watch 🟢 1/1 1/1
watcher.activate_watch 🟢 1/1 1/1
watcher.deactivate_watch 🟢 1/1 1/1
watcher.delete_watch 🟢 2/2 2/2
watcher.execute_watch 🟢 7/7 7/7
watcher.get_settings 🟠 Missing type Missing type
watcher.get_watch 🟢 9/9 9/9
watcher.put_watch 🔴 29/38 38/38
watcher.query_watches Missing test Missing test
watcher.start 🟢 1/1 1/1
watcher.stats 🟢 1/1 1/1
watcher.stop 🟢 1/1 1/1
watcher.update_settings 🟠 Missing type Missing type
xpack.info 🔴 8/8 1/4
xpack.usage 🔴 19/19 0/15

You can validate these APIs yourself by using the make validate target.

@jamietanna
Copy link
Member

jamietanna commented Aug 17, 2023

Great stuff @swallez 👏 I notice that there are a few errors (denoting actual issues with the produced formatting, rather than "nice to have"s) when linting the generated OpenAPI with https://github.com/stoplightio/spectral - just wondering if you're aware of or are validating the schema with any other tools?

Looks like it's largely the following buckets:

  • "url" property must match format "uri-reference"
  • Missing required properties in some cases
  • Path parameters aren't defined, when referenced in paths

There are also some circular references that may break some OpenAPI libraries (it appears to break https://github.com/getkin/kin-openapi)

@swallez
Copy link
Member Author

swallez commented Sep 11, 2023

@jamietanna thanks for the pointer, Spectral is a great linter, picky as it should.

The conversion code has been updated and the linter is happy. The OpenAPI output now comes in two flavors, stack (full API) and serverless.

I still have to implement a few todo for some corner cases before merging this work, but it's now safe to start using the results.

@jamietanna
Copy link
Member

Awesome stuff @swallez 👏 Appreciate the tweaks.

A couple of plumbing points to note:

I believe the circular references may still be an issue (in elasticsearch-openapi.json):

: kin-openapi bug found: circular schema reference not handled - #/components/schemas/_types.query_dsl:QueryContainer -> #/components/schemas/_types.query_dsl:SpanFieldMaskingQuery -> #/components/schemas/_types.query_dsl:SpanQuery -> #/components/schemas/_types.query_dsl:SpanNotQuery -> #/components/schemas/_types.query_dsl:SpanQuery -> #/components/schemas/_types.query_dsl:SpanWithinQuery -> #/components/schemas/_types.query_dsl:SpanQuery -> #/components/schemas/_types.query_dsl:SpanContainingQuery -> #/components/schemas/_types.query_dsl:SpanQuery -> #/components/schemas/_types.query_dsl:SpanFirstQuery -> #/components/schemas/_types.query_dsl:SpanQuery -> #/components/schemas/_types.query_dsl:SpanMultiTermQuery -> #/components/schemas/_types.query_dsl:QueryContainer -> #/components/schemas/_types.query_dsl:FunctionScoreQuery -> #/components/schemas/_types.query_dsl:QueryContainer -> #/components/schemas/_types.query_dsl:PinnedQuery -> #/components/schemas/_types.query_dsl:QueryContainer -> #/components/schemas/_types.query_dsl:ConstantScoreQuery -> #/components/schemas/_types.query_dsl:QueryContainer -> #/components/schemas/_types.query_dsl:ScriptScoreQuery -> #/components/schemas/_types.query_dsl:QueryContainer -> #/components/schemas/_types.query_dsl:RuleQuery -> #/components/schemas/_types.query_dsl:QueryContainer -> #/components/schemas/_types.query_dsl:HasChildQuery -> #/components/schemas/_types.query_dsl:QueryContainer -> #/components/schemas/_types.query_dsl:BoostingQuery -> #/components/schemas/_types.query_dsl:QueryContainer -> #/components/schemas/_types.query_dsl:HasParentQuery -> #/components/schemas/_global.search._types:InnerHits -> #/components/schemas/_types:Sort -> #/components/schemas/_types:SortCombinations -> #/components/schemas/_types:SortOptions -> #/components/schemas/_types:ScriptSort -> #/components/schemas/_types:NestedSortValue -> #/components/schemas/_types:NestedSortValue -> #/components/schemas/_types.query_dsl:QueryContainer -> #/components/schemas/_types.query_dsl:DisMaxQuery -> #/components/schemas/_types.query_dsl:QueryContainer

Some other validators (like spectral) appear to work OK.

There appears to be a clash in one of the related snapshot.create_repository types, but that may be a bug in the code generator.

Key errors I can see in Spectral are:

/home/jamie/workspaces/elasticsearch-specification/output/openapi/elasticsearch-openapi.json
 20265:24  error  path-params  Paths "/_nodes/{node_id}" and "/_nodes/{metric}" must not be equivalent.  paths./_nodes/{metric}
/home/jamie/workspaces/elasticsearch-specification/output/openapi/elasticsearch-serverless-openapi.json
 15946:24  error  path-params  Paths "/_nodes/{node_id}" and "/_nodes/{metric}" must not be equivalent.  paths./_nodes/{metric}

It loosk like elasticsearch-serverless-openapi.json can be used with oapi-codegen, but it generates with some compliation errors, so I'll look at raising a bug for that.

I also note that we've got generated code like:

    "/_async_search/{id}": {
      "get": {
        "description": "Retrieves the results of a previously submitted async search request given its ID.",
        "externalDocs": {
          "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html"
        },
        "operationId": "async_search.get#0",

and

    "schemas": {
      "_types:Id": {
        "type": "string"
      },

Is there anything we can do to maybe massage these into more human-readable names? This may make the generated code that's used with these a little better.

@swallez
Copy link
Member Author

swallez commented Sep 12, 2023

@jamietanna thanks for the feedback.

Regarding the failure of linters and code generators, this has to be put of into perspective with the context and and purpose of this conversion:

  • there's no way we can remove circular dependencies as they're heavily used in the Elasticsearch query DSL. A boolean query contains nested queries, and aggregations can contain nested aggregations. Circular dependencies are indeed an issue to generate code in languages like Go/Rust/C++ that support both structure embedding and structure linking with a reference. This is one of the complex parts of the generator for the Go client. So if a linter or code generator fail on circular types used to represent hierarchical recursive data structures, I consider this to be a bug in these tools, and not a bug in the OpenAPI schema 😉

  • this OpenAPI specification is not meant to generate code: OpenAPI cannot capture a number of the idiosyncrasies of the ES API or language features like generic type parameters that allow generating usable and idiomatic code in the 8 languages we support. This is why the clients team came up with this unconventional approach of using TypeScript to capture the Elasticsearch API request and response bodies. The conversion of this bespoke schema to OpenAPI is meant primarily for generating documentation and other materials for humans (e.g. Kibana auto-completion, CLIs, etc) where these quirks and fine-grained details are not of primary importance and existing OpenAPI tooling can be leveraged.

Regarding the other points you mention:

  • The "/_nodes/{node_id}" and "/_nodes/{metric}" must not be equivalent error is caused by how the Node info API works: the placeholder value can be either a node identifier or a metric name. The server will check if it's a metric name and consider it as a node id otherwise. It's important to keep both variants when generating client libraries, even if these paths are ambiguous from the server point of view.

  • "/_async_search/{id}" and "_types:Id": I'm not sure what you mean here. Is this about removing the _types:Id type and just use string? There are a number of type aliases in the ES API specification meant to provide higher-level semantics to primitive types. Not sure if we should lose this information in the generated OpenAPI as it can be useful in some use cases. So maybe an option in the converter to resolve these type aliases into their primitive target?

@swallez swallez marked this pull request as ready for review October 23, 2023 09:36
@swallez swallez requested a review from a team as a code owner October 23, 2023 09:36
@swallez swallez requested a review from Anaethelion October 23, 2023 10:00
@swallez swallez changed the title OpenAPI converter: initial commit, still WIP Generate OpenAPI schema for Elasticsearch Serverless Oct 23, 2023
Copy link
Contributor

@Anaethelion Anaethelion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd change the name of the main directory from openapi-converter to something meaningful like compiler-rs. There's much more than OpenApi in that folder.

Except for a nit left in a comment, looks great!

}

#[derive(Debug, Clone, PartialEq, ValueEnum)]
pub enum SchemaFlavor {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not reuse the values from client_schema::Flavor ?

Copy link
Member Author

@swallez swallez Oct 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we're likely to have a Common code generation target in the future (currently commented-out) that will be used to retain what's in both Stack and Serverless. So client_schema::Flavor represents the @availability annotation whereas here this represents the generation flavor that can be different from a simple XOR between Stack and Serverless.

@swallez swallez merged commit 11106f0 into main Oct 23, 2023
6 checks passed
@swallez swallez deleted the openapi-converter branch October 23, 2023 15:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants