You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .github/validate-pr/index.js
+4-6Lines changed: 4 additions & 6 deletions
Original file line number
Diff line number
Diff line change
@@ -141,12 +141,10 @@ async function run() {
141
141
}
142
142
comment+=`\nYou can validate ${table.length===1 ? 'this' : 'these'} API${table.length===1 ? '' : 's'} yourself by using the ${tick}make validate${tick} target.\n`
Copy file name to clipboardExpand all lines: api-design-guidelines/data-modelling.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -150,7 +150,7 @@ Or better yet, to completely avoid using dynamic keys the user-defined value can
150
150
151
151
### Model object variants in a consumable way
152
152
153
-
Sometimes an API accepts an object but the keys are determined by what "kind/variant" of the object is intended. An example of this is aggregations, queries, and pipeline steps. There are two ways the Elasticsearch API handles this situation. The first method is using an **internal variant type** property like "type" with analyzers:
153
+
Sometimes an API accepts an object but the keys are determined by what "kind/variant" of the object is intended. An example of this is aggregations, queries, and pipeline steps. There are two ways the Elasticsearch API handles this situation. The first method is using **internal tagging** with property like "type" with analyzers:
154
154
155
155
```yaml
156
156
{
@@ -159,7 +159,7 @@ Sometimes an API accepts an object but the keys are determined by what "kind/var
159
159
}
160
160
```
161
161
162
-
The second is using **external variants** where the inner object is wrapped with an object with a single key containing the kind of the inner object. This example changes the analyzer from above to use an external variant:
162
+
The second is using **external tagging** where the inner object is wrapped with an object with a single key containing the kind of the inner object. This example changes the analyzer from above to use an external variant:
163
163
164
164
```yaml
165
165
{
@@ -169,7 +169,7 @@ The second is using **external variants** where the inner object is wrapped with
169
169
}
170
170
```
171
171
172
-
When choosing between these two possibilities **favor using external variants**as it removes the requirement to buffer key-value pairs until the internal variant property is found. Using external variants also improves traversability of the API (ie auto-complete) as properties can be anticipated without waiting for the discriminant property.
172
+
Internal tagging is a common way to identify variants and should usually be preferred. However, it may have performance implications when used to deserialize large objects in strongly-typed languages. In that case, external tagging should be considered instead, as it removes the requirement to buffer key-value pairs until the internal variant property is found. Using external tagging also improves traversability of the API (ie auto-complete) as properties can be anticipated without waiting for the discriminant property.
Copy file name to clipboardExpand all lines: api-design-guidelines/requests-responses.md
-28Lines changed: 0 additions & 28 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -97,34 +97,6 @@ It's best to use the body for large or high cardinality variable-length request
97
97
- Large objects (Query DSL, aggregations, machine learning models)
98
98
- High cardinality variable length values (list of fields, indices, shards, document IDs)
99
99
100
-
## Adhere to the robustness principle
101
-
102
-
The robustness principle states:
103
-
104
-
> "be conservative in what you do, be liberal in what you accept from others"
105
-
106
-
This principle can apply in a number of ways, but in particular it can determine the design of API requests and responses. An API request may be built flexibly so as to allow both verbose detailed payloads and terse convenience payloads. The corresponding response, however, should always be structured predictably, and not depend on a particular syntax used within the request.
107
-
108
-
As an example, consider an API that looks up entities based on their ID. The request may be structured to allow either a single ID or a collection of IDs to be passed in. However, the API response should always return a collection of entities, even if that collection only contains one entity.
109
-
110
-
This principle allows for simpler consumer code that neither has to remember state between request and response, nor needs to "sniff" the output to determine its structure. If multiple variants of the response are truly desired, this may suggest that multiple API endpoints should be introduced, for example called `get_single_entity` and `get_multiple_entities`.
111
-
112
-
An example of this is the datafeeds API which accepts either a string or list of strings for indices but always returns a list of strings:
113
-
114
-
```yaml
115
-
PUT /_ml/datafeeds/feed-id
116
-
{
117
-
"indices": "index-name", // Input is a string.
118
-
...
119
-
}
120
-
121
-
GET /_ml/datafeeds/feed-id
122
-
{
123
-
"indices": ["index-name"], // Always returns a list of strings.
124
-
...
125
-
}
126
-
```
127
-
128
100
## Consider how client functions would wrap the API endpoint
129
101
130
102
It is common within client-side architecture to provide a one-to-one mapping between API endpoint and client language function. This simplifies implementation and documentation, provides good developer experience, and makes tracking of endpoint usage straightforward.
Copy file name to clipboardExpand all lines: docs/modeling-guide.md
+7-5Lines changed: 7 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -332,7 +332,9 @@ type FooOrBar = Foo | Bar
332
332
333
333
An example of internal variants are the type mapping properties.
334
334
335
-
#### External
335
+
#### typed_keys_quirk
336
+
337
+
**Note**: this feature exists because of some early Elasticsearch APIs where tagging was forgotten, and added after the fact using this quirk to avoid breaking compatibility. **It should not be used for new APIs.**
336
338
337
339
The key that defines the variant is external to the definition, like in the
338
340
case of aggregations in responses or suggesters.
@@ -343,15 +345,15 @@ name in the definition itself.
343
345
The syntax is:
344
346
345
347
```ts
346
-
/**@variantsexternal*/
348
+
/**@variantstyped_keys_quirk*/
347
349
348
350
/**@variant name='<field-name>' */
349
351
```
350
352
351
353
For example:
352
354
353
355
```ts
354
-
/**@variantsexternal*/
356
+
/**@variantstyped_keys_quirk*/
355
357
typeFooAlias=Faz|Bar
356
358
357
359
/**@variant name='faz' */
@@ -369,7 +371,7 @@ In the example above, `FooAlias` will look like this:
0 commit comments