Skip to content
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
2 changes: 2 additions & 0 deletions compiler-rs/clients_schema/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,8 @@ pub struct SchemaExample {
pub value: Option<String>,
pub external_value: Option<String>,
pub alternatives: Option<Vec<ExampleAlternative>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub availability: Option<Availabilities>,
}

/// Common attributes for all type definitions
Expand Down
10 changes: 9 additions & 1 deletion compiler-rs/clients_schema/src/transform/availability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
use std::cell::RefCell;

use crate::transform::Worksheet;
use crate::{Availabilities, Body, IndexedModel, Inherits, Property, TypeDefinition, TypeName, ValueOf};
use crate::{Availabilities, Body, IndexedModel, Inherits, Property, SchemaExample, TypeDefinition, TypeName, ValueOf};

pub struct Availability {
#[allow(clippy::type_complexity)]
Expand Down Expand Up @@ -97,11 +97,13 @@ impl Availability {
self.filter_properties(&mut request.path);
self.filter_properties(&mut request.query);
self.filter_body(&mut request.body);
self.filter_examples(&mut request.examples);
}

TypeDefinition::Response(ref mut response) => {
response.behaviors.iter().for_each(|i| self.filter_behaviors(i));
self.filter_body(&mut response.body);
self.filter_examples(&mut response.examples);
}
}
}
Expand Down Expand Up @@ -163,4 +165,10 @@ impl Availability {
Body::NoBody(_) => {}
}
}

fn filter_examples(&self, examples: &mut Option<indexmap::IndexMap<String, SchemaExample>>) {
if let Some(examples) = examples {
examples.retain(|_, example| self.is_available(&example.availability));
}
}
}
Binary file modified compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib_bg.wasm
Binary file not shown.
2 changes: 2 additions & 0 deletions compiler/src/model/metamodel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ export class Example {
external_value?: string
/** An array of alternatives for this example in other languages */
alternatives?: ExampleAlternative[]
/** Which API flavors this example applies to. Omitted means all flavors. */
availability?: Availabilities
}

/**
Expand Down
30 changes: 30 additions & 0 deletions compiler/src/steps/add-examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ class BaseExamplesProcessor {
if (BaseExamplesProcessor.languageExamples[alternativeKey] !== undefined) {
example.alternatives = BaseExamplesProcessor.languageExamples[alternativeKey]
}
this.normalizeExampleAvailability(example, filePath)
// Some of the example files set their 'value' as a JSON string,
// and some files set their 'value' as an object. For consistency,
// if the value is not a JSON string, convert it to a JSON string.
Expand All @@ -160,6 +161,35 @@ class BaseExamplesProcessor {
}
return examples
}

// Normalize the optional availability field from a YAML list of flavor names
// (e.g. [stack, serverless]) into the Availabilities object used by the metamodel.
// When omitted, the example applies to all flavors.
normalizeExampleAvailability (example: model.Example, filePath: string): void {
const rawAvailability = (example as { availability?: unknown }).availability
if (rawAvailability === undefined || rawAvailability === null) {
delete example.availability
return
}

if (!Array.isArray(rawAvailability)) {
throw new Error(`Example availability in ${filePath} must be a list of flavor names`)
}

const validFlavors = new Set(['stack', 'serverless'])
const availability: model.Availabilities = {}
for (const flavor of rawAvailability) {
if (typeof flavor !== 'string' || !validFlavors.has(flavor)) {
throw new Error(
`Example availability in ${filePath} contains invalid value "${String(flavor)}". ` +
'Accepted values are "stack" and "serverless".'
)
}
availability[flavor as keyof model.Availabilities] = {}
}

example.availability = availability
}
}

/*
Expand Down
14 changes: 14 additions & 0 deletions compiler/src/transform/filter-by-availability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,13 @@ function filterModel (inputModel: Model, stack: boolean, serverless: boolean, vi
typeDef.body.properties = typeDef.body.properties.filter(filterItem())
break
}
if (typeDef.examples !== undefined) {
typeDef.examples = Object.fromEntries(
Object.entries(typeDef.examples).filter(([, example]) =>
(example.availability !== undefined) ? include(example.availability) : true
)
)
}
}
})
break
Expand All @@ -235,6 +242,13 @@ function filterModel (inputModel: Model, stack: boolean, serverless: boolean, vi
typeDef.body.properties = typeDef.body.properties.filter(filterItem())
break
}
if (typeDef.examples !== undefined) {
typeDef.examples = Object.fromEntries(
Object.entries(typeDef.examples).filter(([, example]) =>
(example.availability !== undefined) ? include(example.availability) : true
)
)
}
}
})
break
Expand Down
6 changes: 6 additions & 0 deletions docs/add-new-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@ These examples are for use in the API documentation and must adhere to the [Open
If there are multiple examples for the endpoint, they must each have a brief `summary` field, which is used as the label for the example. You can also optionally provide an explanation in a `description` field.
In order to generate curl and console examples automatically, the request examples must also contain a `method_request`.

If an example applies to only Stack or Serverless Elasticsearch, add an optional `availability` field with a list of flavor names. Accepted values are `stack` and `serverless`. When omitted, the example applies to all contexts. This field works for both request and response examples.

```yaml
availability: [stack]
```

For example:

```yaml
Expand Down
66 changes: 66 additions & 0 deletions docs/examples/languageExamples.json
Original file line number Diff line number Diff line change
Expand Up @@ -19634,5 +19634,71 @@
"language": "curl",
"code": "curl -X PUT -H \"Authorization: ApiKey $ELASTIC_API_KEY\" -H \"Content-Type: application/json\" -d '{\"region_policy\":{\"allowed_regions\":[{\"csp\":\"aws\",\"region\":\"us-east-1\"},{\"csp\":\"aws\",\"region\":\"eu-west-1\"}]}}' \"$ELASTICSEARCH_URL/_inference/_region_policy\""
}
],
"specification/indices/create/examples/request/indicesCreateRequestExample6.yaml": [
{
"language": "Python",
"code": "resp = client.indices.create(\n index=\"test\",\n aliases={\n \"alias_1\": {},\n \"alias_2\": {\n \"filter\": {\n \"term\": {\n \"user.id\": \"kimchy\"\n }\n }\n }\n },\n)"
},
{
"language": "JavaScript",
"code": "const response = await client.indices.create({\n index: \"test\",\n aliases: {\n alias_1: {},\n alias_2: {\n filter: {\n term: {\n \"user.id\": \"kimchy\",\n },\n },\n },\n },\n});"
},
{
"language": "Ruby",
"code": "response = client.indices.create(\n index: \"test\",\n body: {\n \"aliases\": {\n \"alias_1\": {},\n \"alias_2\": {\n \"filter\": {\n \"term\": {\n \"user.id\": \"kimchy\"\n }\n }\n }\n }\n }\n)"
},
{
"language": "PHP",
"code": "$resp = $client->indices()->create([\n \"index\" => \"test\",\n \"body\" => [\n \"aliases\" => [\n \"alias_1\" => new ArrayObject([]),\n \"alias_2\" => [\n \"filter\" => [\n \"term\" => [\n \"user.id\" => \"kimchy\",\n ],\n ],\n ],\n ],\n ],\n]);"
},
{
"language": "curl",
"code": "curl -X PUT -H \"Authorization: ApiKey $ELASTIC_API_KEY\" -H \"Content-Type: application/json\" -d '{\"aliases\":{\"alias_1\":{},\"alias_2\":{\"filter\":{\"term\":{\"user.id\":\"kimchy\"}}}}}' \"$ELASTICSEARCH_URL/test\""
}
],
"specification/indices/create/examples/request/indicesCreateRequestExample4.yaml": [
{
"language": "Python",
"code": "resp = client.indices.create(\n index=\"my-index-000001\",\n)"
},
{
"language": "JavaScript",
"code": "const response = await client.indices.create({\n index: \"my-index-000001\",\n});"
},
{
"language": "Ruby",
"code": "response = client.indices.create(\n index: \"my-index-000001\",\n body: {}\n)"
},
{
"language": "PHP",
"code": "$resp = $client->indices()->create([\n \"index\" => \"my-index-000001\",\n \"body\" => new ArrayObject([]),\n]);"
},
{
"language": "curl",
"code": "curl -X PUT -H \"Authorization: ApiKey $ELASTIC_API_KEY\" -H \"Content-Type: application/json\" -d '{}' \"$ELASTICSEARCH_URL/my-index-000001\""
}
],
"specification/indices/create/examples/request/indicesCreateRequestExample5.yaml": [
{
"language": "Python",
"code": "resp = client.indices.create(\n index=\"test\",\n mappings={\n \"properties\": {\n \"field1\": {\n \"type\": \"text\"\n }\n }\n },\n)"
},
{
"language": "JavaScript",
"code": "const response = await client.indices.create({\n index: \"test\",\n mappings: {\n properties: {\n field1: {\n type: \"text\",\n },\n },\n },\n});"
},
{
"language": "Ruby",
"code": "response = client.indices.create(\n index: \"test\",\n body: {\n \"mappings\": {\n \"properties\": {\n \"field1\": {\n \"type\": \"text\"\n }\n }\n }\n }\n)"
},
{
"language": "PHP",
"code": "$resp = $client->indices()->create([\n \"index\" => \"test\",\n \"body\" => [\n \"mappings\" => [\n \"properties\" => [\n \"field1\" => [\n \"type\" => \"text\",\n ],\n ],\n ],\n ],\n]);"
},
{
"language": "curl",
"code": "curl -X PUT -H \"Authorization: ApiKey $ELASTIC_API_KEY\" -H \"Content-Type: application/json\" -d '{\"mappings\":{\"properties\":{\"field1\":{\"type\":\"text\"}}}}' \"$ELASTICSEARCH_URL/test\""
}
]
}
2 changes: 2 additions & 0 deletions docs/modeling-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,8 @@ export class Example {
}
```

Request and response example YAML files use the same flavor names in an optional `availability` field (for example, `availability: [serverless]`). When omitted, the example applies to both Stack and Serverless.

### Stability property for `@availability`

The `stability` property can be added to an `@availability` annotation to indicate the maturity and expected backwards-compatibility of an API or property.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
summary: Create an index.
availability: [stack]
method_request: PUT /my-index-000001
description: This request specifies the `number_of_shards` and `number_of_replicas`.
# type: request
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
summary: Create an index with mappings.
availability: [stack]
method_request: PUT /test
description: You can provide mapping definitions in the create index API requests.
# type: request
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
summary: Create an index with aliases.
availability: [stack]
method_request: PUT /test
description: >
You can provide mapping definitions in the create index API requests. Index alias names also support date math.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
summary: Create an index.
availability: [serverless]
method_request: PUT /my-index-000001
description: Create an index with default settings.
# type: request
value: '{}'
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
summary: Create an index with mappings.
availability: [serverless]
method_request: PUT /test
description: You can provide mapping definitions in the create index API requests.
# type: request
value: "{

\ \"mappings\": {

\ \"properties\": {

\ \"field1\": { \"type\": \"text\" }

\ }

\ }

}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
summary: Create an index with aliases.
availability: [serverless]
method_request: PUT /test
description: >
You can provide mapping definitions in the create index API requests. Index alias names also support date math.
# type: request
value: "{

\ \"aliases\": {

\ \"alias_1\": {},

\ \"alias_2\": {

\ \"filter\": {

\ \"term\": {

\ \"user.id\": \"kimchy\"

\ }

\ }

\ }

\ }

}"
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
summary: Stack request
availability: [stack]
method_request: POST my-data-stream/_rollover
description: 'Create a new index for a data stream'
# type: request
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
summary: Serverless request
availability: [serverless]
method_request: POST my-data-stream/_rollover
description: 'Create a new index for a data stream'
value: '{}'
2 changes: 2 additions & 0 deletions typescript-generator/src/metamodel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ export class Example {
external_value?: string
/** An array of alternatives for this example in other languages */
alternatives?: ExampleAlternative[]
/** Which API flavors this example applies to. Omitted means all flavors. */
availability?: Availabilities
}

/**
Expand Down
Loading