|
| 1 | +[[changelog-client]] |
| 2 | +== Release notes |
| 3 | + |
| 4 | +[discrete] |
| 5 | +=== 8.0.0 |
| 6 | + |
| 7 | +[discrete] |
| 8 | +==== Features |
| 9 | + |
| 10 | +[discrete] |
| 11 | +[discrete] |
| 12 | +===== Support for Elasticsearch `v8.0` |
| 13 | + |
| 14 | +You can find all the API changes |
| 15 | +https://www.elastic.co/guide/en/elasticsearch/reference/8.0/release-notes-8.0.0.html[here]. |
| 16 | + |
| 17 | +[discrete] |
| 18 | +===== Drop old typescript definitions |
| 19 | + |
| 20 | +*Breaking: Yes* | *Migration effort: Medium* |
| 21 | + |
| 22 | +The current TypeScript definitions will be removed from the client, and the new definitions, which contain request and response definitions as well will be shipped by default. |
| 23 | + |
| 24 | +[discrete] |
| 25 | +===== Drop callback-style API |
| 26 | + |
| 27 | +*Breaking: Yes* | *Migration effort: Large* |
| 28 | + |
| 29 | +Maintaining both API styles is not a problem per se, but it makes error handling more convoluted due to async stack traces. |
| 30 | +Moving to a full-promise API will solve this issue. |
| 31 | + |
| 32 | +[source,js] |
| 33 | +---- |
| 34 | +// callback-style api |
| 35 | +client.search({ params }, { options }, (err, result) => { |
| 36 | + console.log(err || result) |
| 37 | +}) |
| 38 | +
|
| 39 | +// promise-style api |
| 40 | +client.search({ params }, { options }) |
| 41 | + .then(console.log) |
| 42 | + .catch(console.log) |
| 43 | + |
| 44 | +// async-style (sugar syntax on top of promises) |
| 45 | +const response = await client.search({ params }, { options }) |
| 46 | +console.log(response) |
| 47 | +---- |
| 48 | + |
| 49 | +If you are already using the promise-style API, this won't be a breaking change for you. |
| 50 | + |
| 51 | +[discrete] |
| 52 | +===== Remove the current abort API and use the new AbortController standard |
| 53 | + |
| 54 | +*Breaking: Yes* | *Migration effort: Small* |
| 55 | + |
| 56 | +The old abort API makes sense for callbacks but it's annoying to use with promises |
| 57 | + |
| 58 | +[source,js] |
| 59 | +---- |
| 60 | +// callback-style api |
| 61 | +const request = client.search({ params }, { options }, (err, result) => { |
| 62 | + console.log(err) // RequestAbortedError |
| 63 | +}) |
| 64 | +
|
| 65 | +request.abort() |
| 66 | +
|
| 67 | +// promise-style api |
| 68 | +const promise = client.search({ params }, { options }) |
| 69 | +
|
| 70 | +promise |
| 71 | + .then(console.log) |
| 72 | + .catch(console.log) // RequestAbortedError |
| 73 | +
|
| 74 | +promise.abort() |
| 75 | +---- |
| 76 | + |
| 77 | +Node v12 has added the standard https://nodejs.org/api/globals.html#globals_class_abortcontroller[`AbortController`] API which is designed to work well with both callbacks and promises. |
| 78 | +[source,js] |
| 79 | +---- |
| 80 | +const ac = new AbortController() |
| 81 | +client.search({ params }, { signal: ac.signal }) |
| 82 | + .then(console.log) |
| 83 | + .catch(console.log) // RequestAbortedError |
| 84 | +
|
| 85 | +ac.abort() |
| 86 | +---- |
| 87 | + |
| 88 | +[discrete] |
| 89 | +===== Remove the body key from the request |
| 90 | + |
| 91 | +*Breaking: Yes* | *Migration effort: Small* |
| 92 | + |
| 93 | +Thanks to the new types we are developing now we know exactly where a parameter should go. |
| 94 | +The client API leaks HTTP-related notions in many places, and removing them would definitely improve the DX. |
| 95 | + |
| 96 | +This could be a rather big breaking change, so a double solution could be used during the 8.x lifecycle. (accepting body keys without them being wrapped in the body as well as the current solution). |
| 97 | + |
| 98 | +[source,js] |
| 99 | +---- |
| 100 | +// from |
| 101 | +const response = await client.search({ |
| 102 | + index: 'test', |
| 103 | + body: { |
| 104 | + query: { |
| 105 | + match_all: {} |
| 106 | + } |
| 107 | + } |
| 108 | +}) |
| 109 | +
|
| 110 | +// to |
| 111 | +const response = await client.search({ |
| 112 | + index: 'test', |
| 113 | + query: { |
| 114 | + match_all: {} |
| 115 | + } |
| 116 | +}) |
| 117 | +---- |
| 118 | + |
| 119 | +[discrete] |
| 120 | +===== Migrate to new separate transport |
| 121 | + |
| 122 | +*Breaking: Yes* | *Migration effort: Small to none* |
| 123 | + |
| 124 | +The separated transport has been rewritten in TypeScript and has already dropped the callback style API. |
| 125 | +Given that now is separated, most of the Elasticsearch specific concepts have been removed, and the client will likely need to extend parts of it for reintroducing them. |
| 126 | +If you weren't extending the internals of the client, this won't be a breaking change for you. |
| 127 | + |
| 128 | +[discrete] |
| 129 | +===== The returned value of API calls is the body and not the HTTP related keys |
| 130 | + |
| 131 | +*Breaking: Yes* | *Migration effort: Small* |
| 132 | + |
| 133 | +The client API leaks HTTP-related notions in many places, and removing them would definitely improve the DX. |
| 134 | +The client will expose a new request-specific option to still get the full response details. |
| 135 | + |
| 136 | +[source,js] |
| 137 | +---- |
| 138 | +// from |
| 139 | +const response = await client.search({ |
| 140 | + index: 'test', |
| 141 | + body: { |
| 142 | + query: { |
| 143 | + match_all: {} |
| 144 | + } |
| 145 | + } |
| 146 | +}) |
| 147 | +console.log(response) // { body: SearchResponse, statusCode: number, headers: object, warnings: array } |
| 148 | +
|
| 149 | +// to |
| 150 | +const response = await client.search({ |
| 151 | + index: 'test', |
| 152 | + query: { |
| 153 | + match_all: {} |
| 154 | + } |
| 155 | +}) |
| 156 | +console.log(response) // SearchResponse |
| 157 | +
|
| 158 | +// with a bit of TypeScript and JavaScript magic... |
| 159 | +const response = await client.search({ |
| 160 | + index: 'test', |
| 161 | + query: { |
| 162 | + match_all: {} |
| 163 | + } |
| 164 | +}, { |
| 165 | + meta: true |
| 166 | +}) |
| 167 | +console.log(response) // { body: SearchResponse, statusCode: number, headers: object, warnings: array } |
| 168 | +---- |
| 169 | + |
| 170 | +[discrete] |
| 171 | +===== Use a weighted connection pool |
| 172 | + |
| 173 | +*Breaking: Yes* | *Migration effort: Small to none* |
| 174 | + |
| 175 | +Move from the current cluster connection pool to a weight-based implementation. |
| 176 | +This new implementation offers better performances and runs less code in the background, the old connection pool can still be used. |
| 177 | +If you weren't extending the internals of the client, this won't be a breaking change for you. |
| 178 | + |
| 179 | +[discrete] |
| 180 | +===== Migrate to the "undici" http client |
| 181 | + |
| 182 | +*Breaking: Yes* | *Migration effort: Small to none* |
| 183 | + |
| 184 | +By default, the HTTP client will no longer be the default Node.js HTTP client, but https://github.com/nodejs/undici[undici] instead. |
| 185 | +Undici is a brand new HTTP client written from scratch, it offers vastly improved performances and has better support for promises. |
| 186 | +Furthermore, it offers comprehensive and predictable error handling. The old HTTP client can still be used. |
| 187 | +If you weren't extending the internals of the client, this won't be a breaking change for you. |
| 188 | + |
| 189 | +[discrete] |
| 190 | +===== Drop support for old camelCased keys |
| 191 | + |
| 192 | +*Breaking: Yes* | *Migration effort: Medium* |
| 193 | + |
| 194 | +Currently, every path or query parameter could be expressed in both `snake_case` and `camelCase`. Internally the client will convert everything to `snake_case`. |
| 195 | +This was done in an effort to reduce the friction of migrating from the legacy to the new client, but now it no longer makes sense. |
| 196 | +If you are already using `snake_case` keys, this won't be a breaking change for you. |
| 197 | + |
| 198 | +[discrete] |
| 199 | +===== Rename `ssl` option to `tls` |
| 200 | + |
| 201 | +*Breaking: Yes* | *Migration effort: Small* |
| 202 | + |
| 203 | +People usually refers to this as `tls`, furthermore, internally we use the tls API and Node.js refers to it as tls everywhere. |
| 204 | +[source,js] |
| 205 | +---- |
| 206 | +// before |
| 207 | +const client = new Client({ |
| 208 | + node: 'https://localhost:9200', |
| 209 | + ssl: { |
| 210 | + rejectUnauthorized: false |
| 211 | + } |
| 212 | +}) |
| 213 | +
|
| 214 | +// after |
| 215 | +const client = new Client({ |
| 216 | + node: 'https://localhost:9200', |
| 217 | + tls: { |
| 218 | + rejectUnauthorized: false |
| 219 | + } |
| 220 | +}) |
| 221 | +---- |
| 222 | + |
| 223 | +[discrete] |
| 224 | +===== Remove prototype poisoning protection |
| 225 | + |
| 226 | +*Breaking: Yes* | *Migration effort: Small* |
| 227 | + |
| 228 | +Prototype poisoning protection is very useful, but it can cause performances issues with big payloads. |
| 229 | +In v8 it will be removed, and the documentation will show how to add it back with a custom serializer. |
| 230 | + |
| 231 | +[discrete] |
| 232 | +===== Remove client extensions API |
| 233 | + |
| 234 | +*Breaking: Yes* | *Migration effort: Large* |
| 235 | + |
| 236 | +Nowadays the client support the entire Elasticsearch API, and the `transport.request` method can be used if necessary. The client extensions API have no reason to exist. |
| 237 | +[source,js] |
| 238 | +---- |
| 239 | +client.extend('utility.index', ({ makeRequest }) => { |
| 240 | + return function _index (params, options) { |
| 241 | + // your code |
| 242 | + } |
| 243 | +}) |
| 244 | +
|
| 245 | +client.utility.index(...) |
| 246 | +---- |
| 247 | + |
| 248 | +If you weren't using client extensions, this won't be a breaking change for you. |
| 249 | + |
| 250 | +[discrete] |
| 251 | +===== Move to TypeScript |
| 252 | + |
| 253 | +*Breaking: No* | *Migration effort: None* |
| 254 | + |
| 255 | +The new separated transport is already written in TypeScript, and it makes sense that the client v8 will be fully written in TypeScript as well. |
| 256 | + |
| 257 | +[discrete] |
| 258 | +===== Move from emitter-like interface to a diagnostic method |
| 259 | + |
| 260 | +*Breaking: Yes* | *Migration effort: Small* |
| 261 | + |
| 262 | +Currently, the client offers a subset of methods of the `EventEmitter` class, v8 will ship with a `diagnostic` property which will be a proper event emitter. |
| 263 | +[source,js] |
| 264 | +---- |
| 265 | +// from |
| 266 | +client.on('request', console.log) |
| 267 | +
|
| 268 | +// to |
| 269 | +client.diagnostic.on('request', console.log) |
| 270 | +---- |
| 271 | + |
| 272 | +[discrete] |
| 273 | +===== Remove username & password properties from Cloud configuration |
| 274 | + |
| 275 | +*Breaking: Yes* | *Migration effort: Small* |
| 276 | + |
| 277 | +The Cloud configuration does not support ApiKey and Bearer auth, while the `auth` options does. |
| 278 | +There is no need to keep the legacy basic auth support in the cloud configuration. |
| 279 | +[source,js] |
| 280 | +---- |
| 281 | +// before |
| 282 | +const client = new Client({ |
| 283 | + cloud: { |
| 284 | + id: '<cloud-id>', |
| 285 | + username: 'elastic', |
| 286 | + password: 'changeme' |
| 287 | + } |
| 288 | +}) |
| 289 | +
|
| 290 | +// after |
| 291 | +const client = new Client({ |
| 292 | + cloud: { |
| 293 | + id: '<cloud-id>' |
| 294 | + }, |
| 295 | + auth: { |
| 296 | + username: 'elastic', |
| 297 | + password: 'changeme' |
| 298 | + } |
| 299 | +}) |
| 300 | +---- |
| 301 | + |
| 302 | +If you are already passing the basic auth options in the `auth` configuration, this won't be a breaking change for you. |
| 303 | + |
| 304 | +[discrete] |
| 305 | +===== Calling `client.close` will reject new requests |
| 306 | + |
| 307 | +Once you call `client.close` every new request after that will be rejected with a `NoLivingConnectionsError`. In-flight requests will be executed normally unless an in-flight request requires a retry, in which case it will be rejected. |
0 commit comments