From 759138c3751baa939f74b620274f2d46d60120fc Mon Sep 17 00:00:00 2001 From: Tomas Della Vedova Date: Fri, 11 Feb 2022 10:23:07 +0100 Subject: [PATCH] Update docs for v8 (#1572) --- README.md | 75 +--- docs/advanced-config.asciidoc | 4 +- docs/basic-config.asciidoc | 28 +- docs/breaking-changes.asciidoc | 334 ------------------ docs/child.asciidoc | 4 +- docs/configuration.asciidoc | 1 - docs/connecting.asciidoc | 159 +++------ docs/examples/asStream.asciidoc | 29 +- docs/examples/bulk.asciidoc | 8 +- docs/examples/exists.asciidoc | 6 +- docs/examples/get.asciidoc | 6 +- docs/examples/ignore.asciidoc | 8 +- docs/examples/index.asciidoc | 2 - docs/examples/msearch.asciidoc | 10 +- docs/examples/proxy/api/autocomplete.js | 22 +- docs/examples/proxy/api/delete.js | 2 +- docs/examples/proxy/api/index.js | 5 +- docs/examples/proxy/api/search.js | 8 +- docs/examples/proxy/package.json | 2 +- .../proxy/utils/prepare-elasticsearch.js | 20 +- docs/examples/reindex.asciidoc | 40 +-- docs/examples/scroll.asciidoc | 26 +- docs/examples/search.asciidoc | 18 +- docs/examples/sql.query.asciidoc | 18 +- docs/examples/suggest.asciidoc | 24 +- docs/examples/transport.request.asciidoc | 8 +- docs/examples/typescript.asciidoc | 72 ---- docs/examples/update.asciidoc | 32 +- docs/examples/update_by_query.asciidoc | 28 +- docs/extend.asciidoc | 72 ---- docs/helpers.asciidoc | 35 +- docs/index.asciidoc | 1 - docs/installation.asciidoc | 8 +- docs/introduction.asciidoc | 93 +---- docs/observability.asciidoc | 76 ++-- docs/testing.asciidoc | 6 +- docs/typescript.asciidoc | 289 +++------------ 37 files changed, 315 insertions(+), 1264 deletions(-) delete mode 100644 docs/breaking-changes.asciidoc delete mode 100644 docs/examples/typescript.asciidoc delete mode 100644 docs/extend.asciidoc diff --git a/README.md b/README.md index 5d06668ac..66cd87671 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ of `^7.10.0`). | --------------- |------------------| ---------------------- | | `8.x` | `December 2019` | `7.11` (early 2021) | | `10.x` | `April 2021` | `7.12` (mid 2021) | +| `12.x` | `April 2022` | `8.2` (early 2022) | ### Compatibility @@ -53,7 +54,7 @@ Elasticsearch language clients are only backwards compatible with default distri | Elasticsearch Version | Client Version | | --------------------- |----------------| -| `main` | `main` | +| `8.x` | `8.x` | | `7.x` | `7.x` | | `6.x` | `6.x` | | `5.x` | `5.x` | @@ -74,11 +75,9 @@ We recommend that you write a lightweight proxy that uses this client instead, y - [Usage](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-connecting.html#client-usage) - [Client configuration](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-configuration.html) - [API reference](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html) -- [Breaking changes coming from the old client](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/breaking-changes.html) - [Authentication](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-connecting.html#authentication) - [Observability](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/observability.html) - [Creating a child client](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/child.html) -- [Extend the client](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/extend.html) - [Client helpers](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-helpers.html) - [Typescript support](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/typescript.html) - [Testing](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-testing.html) @@ -86,48 +85,6 @@ We recommend that you write a lightweight proxy that uses this client instead, y ## Quick start -First of all, require the client and initialize it: -```js -const { Client } = require('@elastic/elasticsearch') -const client = new Client({ node: 'http://localhost:9200' }) -``` - -You can use both the callback-style API and the promise-style API, both behave the same way. -```js -// promise API -const result = await client.search({ - index: 'my-index', - body: { - query: { - match: { hello: 'world' } - } - } -}) - -// callback API -client.search({ - index: 'my-index', - body: { - query: { - match: { hello: 'world' } - } - } -}, (err, result) => { - if (err) console.log(err) -}) -``` -The returned value of **every** API call is formed as follows: -```ts -{ - body: object | boolean - statusCode: number - headers: object - warnings: [string] - meta: object -} -``` - -Let's see a complete example! ```js 'use strict' @@ -138,8 +95,7 @@ async function run () { // Let's start by indexing some data await client.index({ index: 'game-of-thrones', - // type: '_doc', // uncomment this line if you are using Elasticsearch ≤ 6 - body: { + document: { character: 'Ned Stark', quote: 'Winter is coming.' } @@ -147,8 +103,7 @@ async function run () { await client.index({ index: 'game-of-thrones', - // type: '_doc', // uncomment this line if you are using Elasticsearch ≤ 6 - body: { + document: { character: 'Daenerys Targaryen', quote: 'I am the blood of the dragon.' } @@ -156,8 +111,7 @@ async function run () { await client.index({ index: 'game-of-thrones', - // type: '_doc', // uncomment this line if you are using Elasticsearch ≤ 6 - body: { + document: { character: 'Tyrion Lannister', quote: 'A mind needs books like a sword needs a whetstone.' } @@ -168,17 +122,14 @@ async function run () { await client.indices.refresh({ index: 'game-of-thrones' }) // Let's search! - const { body } = await client.search({ + const result= await client.search({ index: 'game-of-thrones', - // type: '_doc', // uncomment this line if you are using Elasticsearch ≤ 6 - body: { - query: { - match: { quote: 'winter' } - } + query: { + match: { quote: 'winter' } } }) - console.log(body.hits.hits) + console.log(result.hits.hits) } run().catch(console.log) @@ -211,13 +162,13 @@ const { Client: Client7 } = require('es7') const client6 = new Client6({ node: 'http://localhost:9200' }) const client7 = new Client7({ node: 'http://localhost:9201' }) -client6.info(console.log) -client7.info(console.log) +client6.info().then(console.log, console.log) +client7.info().then(console.log, console.log) ``` -Finally, if you want to install the client for the next version of Elasticsearch *(the one that lives in Elasticsearch’s master branch)*, you can use the following command: +Finally, if you want to install the client for the next version of Elasticsearch *(the one that lives in Elasticsearch’s main branch)*, you can use the following command: ```sh -npm install esmaster@github:elastic/elasticsearch-js +npm install esmain@github:elastic/elasticsearch-js ``` ## License diff --git a/docs/advanced-config.asciidoc b/docs/advanced-config.asciidoc index 1308b806a..34eb3d750 100644 --- a/docs/advanced-config.asciidoc +++ b/docs/advanced-config.asciidoc @@ -45,9 +45,9 @@ is performed here, this means that if you want to swap the default HTTP client [source,js] ---- -const { Client, Connection } = require('@elastic/elasticsearch') +const { Client, BaseConnection } = require('@elastic/elasticsearch') -class MyConnection extends Connection { +class MyConnection extends BaseConnection { request (params, callback) { // your code } diff --git a/docs/basic-config.asciidoc b/docs/basic-config.asciidoc index c9b4660dd..363326f20 100644 --- a/docs/basic-config.asciidoc +++ b/docs/basic-config.asciidoc @@ -32,7 +32,7 @@ Or it can be an object (or an array of objects) that represents the node: ---- node: { url: new URL('http://localhost:9200'), - ssl: 'ssl options', + tls: 'tls options', agent: 'http agent options', id: 'custom node id', headers: { 'custom': 'headers' } @@ -118,8 +118,8 @@ _Default:_ `false` _Options:_ `'gzip'`, `false` + _Default:_ `false` -|`ssl` -|`http.SecureContextOptions` - ssl https://nodejs.org/api/tls.html[configuraton]. + +|`tls` +|`http.SecureContextOptions` - tls https://nodejs.org/api/tls.html[configuraton]. + _Default:_ `null` |`proxy` @@ -267,24 +267,4 @@ _Default:_ `null` |`number` - When configured, it verifies that the compressed response size is lower than the configured number, if it's higher it will abort the request. It cannot be higher than buffer.constants.MAX_LENTGH + _Default:_ `null` -|=== - -[discrete] -==== Performances considerations - -By default, the client will protection you against prototype poisoning attacks. -Read https://web.archive.org/web/20200319091159/https://hueniverse.com/square-brackets-are-the-enemy-ff5b9fd8a3e8?gi=184a27ee2a08[this article] to learn more. -If needed you can disable prototype poisoning protection entirely or one of the two checks. -Read the `secure-json-parse` https://github.com/fastify/secure-json-parse[documentation] to learn more. - -While it's good to be safe, you should know that security always comes with a cost. -With big enough payloads, this security check could causea drop in the overall performances, -which might be a problem for your application. -If you know you can trust the data stored in Elasticsearch, you can safely disable this check. - -[source,js] ----- -const client = new Client({ - disablePrototypePoisoningProtection: true -}) ----- +|=== \ No newline at end of file diff --git a/docs/breaking-changes.asciidoc b/docs/breaking-changes.asciidoc deleted file mode 100644 index 9942eb9a8..000000000 --- a/docs/breaking-changes.asciidoc +++ /dev/null @@ -1,334 +0,0 @@ -[[breaking-changes]] -=== Breaking changes coming from the old client - -If you were already using the previous version of this client – the one you used -to install with `npm install elasticsearch` – you will encounter some breaking -changes. - - -[discrete] -==== Don’t panic! - -Every breaking change was carefully weighed, and each is justified. Furthermore, -the new codebase has been rewritten with modern JavaScript and has been -carefully designed to be easy to maintain. - - -[discrete] -==== Breaking changes - -* Minimum supported version of Node.js is `v8`. - -* Everything has been rewritten using ES6 classes to help users extend the -defaults more easily. - -* There is no longer an integrated logger. The client now is an event emitter -that emits the following events: `request`, `response`, and `error`. - -* The code is no longer shipped with all the versions of the API, but only that -of the package’s major version. This means that if you are using {es} `v6`, you -are required to install `@elastic/elasticsearch@6`, and so on. - -* The internals are completely different, so if you used to tweak them a lot, -you will need to refactor your code. The public API should be almost the same. - -* There is no longer browser support, for that will be distributed via another -module: `@elastic/elasticsearch-browser`. This module is intended for Node.js -only. - -* The returned value of an API call will no longer be the `body`, `statusCode`, -and `headers` for callbacks, and only the `body` for promises. The new returned -value will be a unique object containing the `body`, `statusCode`, `headers`, -`warnings`, and `meta`, for both callback and promises. - - -[source,js] ----- -// before -const body = await client.search({ - index: 'my-index', - body: { foo: 'bar' } -}) - -client.search({ - index: 'my-index', - body: { foo: 'bar' } -}, (err, body, statusCode, headers) => { - if (err) console.log(err) -}) - -// after -const { body, statusCode, headers, warnings } = await client.search({ - index: 'my-index', - body: { foo: 'bar' } -}) - -client.search({ - index: 'my-index', - body: { foo: 'bar' } -}, (err, { body, statusCode, headers, warnings }) => { - if (err) console.log(err) -}) ----- - - -* Errors: there is no longer a custom error class for every HTTP status code -(such as `BadRequest` or `NotFound`). There is instead a single `ResponseError`. -Every error class has been renamed, and now each is suffixed with `Error` at the -end. - -* Removed errors: `RequestTypeError`, `Generic`, and all the status code -specific errors (such as `BadRequest` or `NotFound`). - -* Added errors: `ConfigurationError` (in case of bad configurations) and -`ResponseError` that contains all the data you may need to handle the specific -error, such as `statusCode`, `headers`, `body`, and `message`. - - -* Renamed errors: - -** `RequestTimeout` (408 statusCode) => `TimeoutError` -** `ConnectionFault` => `ConnectionError` -** `NoConnections` => `NoLivingConnectionsError` -** `Serialization` => `SerializationError` -** `Serialization` => `DeserializationError` - -* You must specify the port number in the configuration. In the previous -version, you can specify the host and port in a variety of ways. With the new -client, there is only one way to do it, via the `node` parameter. - -* Certificates are verified by default, if you want to disable certificates verification, you should set the `rejectUnauthorized` option to `false` inside the `ssl` configuration: - -[source,js] ----- -const { Client } = require('@elastic/elasticsearch') -const client = new Client({ - ssl: { rejectUnauthorized: false } -}) ----- - -* The `plugins` option has been removed. If you want to extend the client now, -you should use the `client.extend` API. - -[source,js] ----- -// before -const { Client } = require('elasticsearch') -const client = new Client({ plugins: [...] }) - -// after -const { Client } = require('@elastic/elasticsearch') -const client = new Client({ ... }) -client.extend(...) ----- - -* There is a clear distinction between the API related parameters and the client -related configurations. The parameters `ignore`, `headers`, `requestTimeout` and -`maxRetries` are no longer part of the API object and you need to specify them -in a second option object. - -[source,js] ----- -// before -const body = await client.search({ - index: 'my-index', - body: { foo: 'bar' }, - ignore: [404] -}) - -client.search({ - index: 'my-index', - body: { foo: 'bar' }, - ignore: [404] -}, (err, body, statusCode, headers) => { - if (err) console.log(err) -}) - -// after -const { body, statusCode, headers, warnings } = await client.search({ - index: 'my-index', - body: { foo: 'bar' } -}, { - ignore: [404] -}) - -client.search({ - index: 'my-index', - body: { foo: 'bar' } -}, { - ignore: [404] -}, (err, { body, statusCode, headers, warnings }) => { - if (err) console.log(err) -}) ----- - -* The `transport.request` method no longer accepts the `query` key. Use the -`querystring` key instead (which can be a string or an object). You also -need to send a bulk-like request instead of the `body` key, use the `bulkBody` -key. In this method, the client specific parameters should be passed as a second -object. - -[source,js] ----- -// before -const body = await client.transport.request({ - method: 'GET', - path: '/my-index/_search', - body: { foo: 'bar' }, - query: { bar: 'baz' } - ignore: [404] -}) - -client.transport.request({ - method: 'GET', - path: '/my-index/_search', - body: { foo: 'bar' }, - query: { bar: 'baz' } - ignore: [404] -}, (err, body, statusCode, headers) => { - if (err) console.log(err) -}) - -// after -const { body, statusCode, headers, warnings } = await client.transport.request({ - method: 'GET', - path: '/my-index/_search', - body: { foo: 'bar' }, - querystring: { bar: 'baz' } -}, { - ignore: [404] -}) - -client.transport.request({ - method: 'GET', - path: '/my-index/_search', - body: { foo: 'bar' }, - querystring: { bar: 'baz' } -}, { - ignore: [404] -}, (err, { body, statusCode, headers, warnings }) => { - if (err) console.log(err) -}) ----- - -[discrete] -==== Talk is cheap. Show me the code. - -You can find a code snippet with the old client below followed by the same code -logic but with the new client. - -[source,js] ----- -const { Client, errors } = require('elasticsearch') -const client = new Client({ - host: 'http://localhost:9200', - plugins: [utility] -}) - -async function run () { - try { - const body = await client.search({ - index: 'game-of-thrones', - body: { - query: { - match: { quote: 'winter' } - } - } - ignore: [404] - }) - console.log(body) - } catch (err) { - if (err instanceof errors.BadRequest) { - console.log('Bad request') - } else { - console.log(err) - } - } -} - -function utility (Client, config, components) { - const ca = components.clientAction.factory - Client.prototype.utility = components.clientAction.namespaceFactory() - const utility = Client.prototype.utility.prototype - - utility.index = ca({ - params: { - refresh: { - type: 'enum', - options: [ - 'true', - 'false', - 'wait_for', - '' - ] - }, - }, - urls: [ - { - fmt: '/<%=index%>/_doc', - req: { - index: { - type: 'string', - required: true - } - } - } - ], - needBody: true, - method: 'POST' - }) -}) ----- - -And now with the new client. - -[source,js] ----- -const { Client, errors } = require('@elastic/elasticsearch') -// NOTE: `host` has been renamed to `node`, -// and `plugins` is no longer supported -const client = new Client({ node: 'http://localhost:9200' }) - -async function run () { - try { - // NOTE: we are using the destructuring assignment - const { body } = await client.search({ - index: 'game-of-thrones', - body: { - query: { - match: { quote: 'winter' } - } - } - // NOTE: `ignore` now is in a separated object - }, { - ignore: [404] - }) - console.log(body) - } catch (err) { - // NOTE: we are checking the `statusCode` property - if (err.statusCode === 400) { - console.log('Bad request') - } else { - console.log(err) - } - } -} - -// NOTE: we can still extend the client, but with a different API. -// This new API is a little bit more verbose, since you must write -// your own validations, but it's way more flexible. -client.extend('utility.index', ({ makeRequest, ConfigurationError }) => { - return function utilityIndex (params, options) { - const { body, index, ...querystring } = params - if (body == null) throw new ConfigurationError('Missing body') - if (index == null) throw new ConfigurationError('Missing index') - const requestParams = { - method: 'POST', - path: `/${index}/_doc`, - body: body, - querystring - } - return makeRequest(requestParams, options) - } -}) ----- diff --git a/docs/child.asciidoc b/docs/child.asciidoc index 9c06c9f25..5e1abdee7 100644 --- a/docs/child.asciidoc +++ b/docs/child.asciidoc @@ -28,6 +28,6 @@ const child = client.child({ requestTimeout: 1000 }) -client.info(console.log) -child.info(console.log) +client.info().then(console.log, console.log) +child.info().then(console.log, console.log) ---- \ No newline at end of file diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc index 2cd2114a8..e5c4f32f8 100644 --- a/docs/configuration.asciidoc +++ b/docs/configuration.asciidoc @@ -8,5 +8,4 @@ section, you can see the possible options that you can use to configure it. * <> * <> * <> -* <> * <> diff --git a/docs/connecting.asciidoc b/docs/connecting.asciidoc index 03bc4532d..57510ae12 100644 --- a/docs/connecting.asciidoc +++ b/docs/connecting.asciidoc @@ -32,7 +32,7 @@ the `auth` option. NOTE: When connecting to Elastic Cloud, the client will automatically enable both request and response compression by default, since it yields significant -throughput improvements. Moreover, the client will also set the ssl option +throughput improvements. Moreover, the client will also set the tls option `secureProtocol` to `TLSv1_2_method` unless specified otherwise. You can still override this option by configuring them. @@ -151,13 +151,13 @@ const client = new Client({ [discrete] -[[auth-ssl]] -==== SSL configuration +[[auth-tls]] +==== TLS configuration Without any additional configuration you can specify `https://` node urls, and the certificates used to sign these requests will be verified. To turn off -certificate verification, you must specify an `ssl` object in the top level -config and set `rejectUnauthorized: false`. The default `ssl` values are the +certificate verification, you must specify an `tls` object in the top level +config and set `rejectUnauthorized: false`. The default `tls` values are the same that Node.js's https://nodejs.org/api/tls.html#tls_tls_connect_options_callback[`tls.connect()`] uses. @@ -170,7 +170,7 @@ const client = new Client({ username: 'elastic', password: 'changeme' }, - ssl: { + tls: { ca: fs.readFileSync('./cacert.pem'), rejectUnauthorized: false } @@ -193,7 +193,7 @@ const client = new Client({ auth: { ... }, // the fingerprint (SHA256) of the CA certificate that is used to sign the certificate that the Elasticsearch node presents for TLS. caFingerprint: '20:0D:CA:FA:76:...', - ssl: { + tls: { // might be required if it's a self-signed certificate rejectUnauthorized: false } @@ -214,31 +214,32 @@ and every method exposes the same signature. const { Client } = require('@elastic/elasticsearch') const client = new Client({ node: 'http://localhost:9200' }) -// promise API const result = await client.search({ index: 'my-index', - body: { - query: { - match: { hello: 'world' } - } + query: { + match: { hello: 'world' } } }) - -// callback API -client.search({ - index: 'my-index', - body: { - query: { - match: { hello: 'world' } - } - } -}, (err, result) => { - if (err) console.log(err) -}) ---- -The returned value of every API call is designed as follows: +The returned value of every API call is the response body from {es}. +If you need to access additonal metadata, such as the status code or headers, +you must specify `meta: true` in the request options: +[source,js] +---- +const { Client } = require('@elastic/elasticsearch') +const client = new Client({ node: 'http://localhost:9200' }) + +const result = await client.search({ + index: 'my-index', + query: { + match: { hello: 'world' } + } +}, { meta: true }) +---- + +In this case, the result will be: [source,ts] ---- { @@ -252,44 +253,10 @@ The returned value of every API call is designed as follows: NOTE: The body is a boolean value when you use `HEAD` APIs. -The above value is returned even if there is an error during the execution of -the request, this means that you can safely use the -https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment[destructuring assignment]. - -The `meta` key contains all the information about the request, such as attempt, -options, and the connection that has been used. - -[source,js] ----- -// promise API -const { body } = await client.search({ - index: 'my-index', - body: { - query: { - match: { hello: 'world' } - } - } -}) - -// callback API -client.search({ - index: 'my-index', - body: { - query: { - match: { hello: 'world' } - } - } -}, (err, { body }) => { - if (err) console.log(err) -}) ----- - - [discrete] ==== Aborting a request -If needed, you can abort a running request by calling the `request.abort()` -method returned by the API. +If needed, you can abort a running request by using the `AbortController` standard. CAUTION: If you abort a request, the request will fail with a `RequestAbortedError`. @@ -297,51 +264,21 @@ CAUTION: If you abort a request, the request will fail with a [source,js] ---- -const request = client.search({ +const AbortController = require('node-abort-controller') +const { Client } = require('@elastic/elasticsearch') +const client = new Client({ node: 'http://localhost:9200' }) + +const abortController = new AbortController() +setImmediate(() => abortController.abort()) + +const result = await client.search({ index: 'my-index', - body: { - query: { - match: { hello: 'world' } - } + query: { + match: { hello: 'world' } } -}, { - ignore: [404], - maxRetries: 3 -}, (err, result) => { - if (err) { - console.log(err) // RequestAbortedError - } else { - console.log(result) - } -}) - -request.abort() +}, { signal: abortController.signal }) ---- -The same behavior is valid for the promise style API as well. - -[source,js] ----- -const request = client.search({ - index: 'my-index', - body: { - query: { - match: { hello: 'world' } - } - } -}, { - ignore: [404], - maxRetries: 3 -}) - -request - .then(result => console.log(result)) - .catch(err => console.log(err)) // RequestAbortedError - -request.abort() ----- - - [discrete] ==== Request specific options @@ -349,7 +286,6 @@ If needed you can pass request specific options in a second object: [source,js] ---- -// promise API const result = await client.search({ index: 'my-index', body: { @@ -361,21 +297,6 @@ const result = await client.search({ ignore: [404], maxRetries: 3 }) - -// callback API -client.search({ - index: 'my-index', - body: { - query: { - match: { hello: 'world' } - } - } -}, { - ignore: [404], - maxRetries: 3 -}, (err, { body }) => { - if (err) console.log(err) -}) ---- @@ -427,6 +348,10 @@ _Default:_ `null` |`number` - When configured, it verifies that the compressed response size is lower than the configured number, if it's higher it will abort the request. It cannot be higher than buffer.constants.MAX_LENTGH + _Default:_ `null` +|`signal` +|`AbortSignal` - The AbortSignal instance to allow request abortion. + +_Default:_ `null` + |=== [discrete] diff --git a/docs/examples/asStream.asciidoc b/docs/examples/asStream.asciidoc index a80fd549b..dd7f9f21a 100644 --- a/docs/examples/asStream.asciidoc +++ b/docs/examples/asStream.asciidoc @@ -12,9 +12,9 @@ const { Client } = require('@elastic/elasticsearch') const client = new Client({ node: 'http://localhost:9200' }) async function run () { - const { body: bulkResponse } = await client.bulk({ + const bulkResponse = await client.bulk({ refresh: true, - body: [ + operations: [ // operation to perform { index: { _index: 'game-of-thrones' } }, // the document to index @@ -43,13 +43,11 @@ async function run () { } // Let's search! - const { body } = await client.search({ + const result = await client.search({ index: 'game-of-thrones', - body: { - query: { - match: { - quote: 'winter' - } + query: { + match: { + quote: 'winter' } } }, { @@ -59,17 +57,17 @@ async function run () { // stream async iteration, available in Node.js ≥ 10 let payload = '' body.setEncoding('utf8') - for await (const chunk of body) { + for await (const chunk of result) { payload += chunk } console.log(JSON.parse(payload)) // classic stream callback style let payload = '' - body.setEncoding('utf8') - body.on('data', chunk => { payload += chunk }) - body.on('error', console.log) - body.on('end', () => { + result.setEncoding('utf8') + result.on('data', chunk => { payload += chunk }) + result.on('error', console.log) + result.on('end', () => { console.log(JSON.parse(payload)) }) } @@ -91,9 +89,10 @@ const fastify = require('fastify')() fastify.post('/search/:index', async (req, reply) => { const { body, statusCode, headers } = await client.search({ index: req.params.index, - body: req.body + ...req.body }, { - asStream: true + asStream: true, + meta: true }) reply.code(statusCode).headers(headers) diff --git a/docs/examples/bulk.asciidoc b/docs/examples/bulk.asciidoc index 2f05b4cf1..e7d9261be 100644 --- a/docs/examples/bulk.asciidoc +++ b/docs/examples/bulk.asciidoc @@ -19,7 +19,7 @@ const client = new Client({ async function run () { await client.indices.create({ index: 'tweets', - body: { + operations: { mappings: { properties: { id: { type: 'integer' }, @@ -58,9 +58,9 @@ async function run () { date: new Date() }] - const body = dataset.flatMap(doc => [{ index: { _index: 'tweets' } }, doc]) + const operations = dataset.flatMap(doc => [{ index: { _index: 'tweets' } }, doc]) - const { body: bulkResponse } = await client.bulk({ refresh: true, body }) + const bulkResponse = await client.bulk({ refresh: true, operations }) if (bulkResponse.errors) { const erroredDocuments = [] @@ -84,7 +84,7 @@ async function run () { console.log(erroredDocuments) } - const { body: count } = await client.count({ index: 'tweets' }) + const count = await client.count({ index: 'tweets' }) console.log(count) } diff --git a/docs/examples/exists.asciidoc b/docs/examples/exists.asciidoc index 851f8c471..368f4ae2b 100644 --- a/docs/examples/exists.asciidoc +++ b/docs/examples/exists.asciidoc @@ -16,18 +16,18 @@ async function run () { await client.index({ index: 'game-of-thrones', id: '1', - body: { + document: { character: 'Ned Stark', quote: 'Winter is coming.' } }) - const { body } = await client.exists({ + const exists = await client.exists({ index: 'game-of-thrones', id: 1 }) - console.log(body) // true + console.log(exists) // true } run().catch(console.log) diff --git a/docs/examples/get.asciidoc b/docs/examples/get.asciidoc index 18caf1f4d..9302c7607 100644 --- a/docs/examples/get.asciidoc +++ b/docs/examples/get.asciidoc @@ -16,18 +16,18 @@ async function run () { await client.index({ index: 'game-of-thrones', id: '1', - body: { + document: { character: 'Ned Stark', quote: 'Winter is coming.' } }) - const { body } = await client.get({ + const document = await client.get({ index: 'game-of-thrones', id: '1' }) - console.log(body) + console.log(document) } run().catch(console.log) diff --git a/docs/examples/ignore.asciidoc b/docs/examples/ignore.asciidoc index a46f3e708..40b570726 100644 --- a/docs/examples/ignore.asciidoc +++ b/docs/examples/ignore.asciidoc @@ -11,9 +11,9 @@ const { Client } = require('@elastic/elasticsearch') const client = new Client({ node: 'http://localhost:9200' }) async function run () { - const { body: bulkResponse } = await client.bulk({ + const bulkResponse = await client.bulk({ refresh: true, - body: [ + operations: [ // operation to perform { index: { _index: 'game-of-thrones' } }, // the document to index @@ -42,7 +42,7 @@ async function run () { } // Let's search! - const { body } = await client.search({ + const result = await client.search({ index: 'game-of-thrones', body: { query: { @@ -55,7 +55,7 @@ async function run () { ignore: [404] }) - console.log(body) // ResponseError + console.log(result) // ResponseError } run().catch(console.log) diff --git a/docs/examples/index.asciidoc b/docs/examples/index.asciidoc index 7aaf38f56..e786675ec 100644 --- a/docs/examples/index.asciidoc +++ b/docs/examples/index.asciidoc @@ -17,7 +17,6 @@ Following you can find some examples on how to use the client. * Executing a <> request; * I need <>; * How to use the <> method; -* How to use <>; include::asStream.asciidoc[] include::bulk.asciidoc[] @@ -29,7 +28,6 @@ include::scroll.asciidoc[] include::search.asciidoc[] include::suggest.asciidoc[] include::transport.request.asciidoc[] -include::typescript.asciidoc[] include::sql.query.asciidoc[] include::update.asciidoc[] include::update_by_query.asciidoc[] diff --git a/docs/examples/msearch.asciidoc b/docs/examples/msearch.asciidoc index 3773318f4..445bf866c 100644 --- a/docs/examples/msearch.asciidoc +++ b/docs/examples/msearch.asciidoc @@ -12,9 +12,9 @@ const { Client } = require('@elastic/elasticsearch') const client = new Client({ node: 'http://localhost:9200' }) async function run () { - const { body: bulkResponse } = await client.bulk({ + const bulkResponse = await client.bulk({ refresh: true, - body: [ + operations: [ { index: { _index: 'game-of-thrones' } }, { character: 'Ned Stark', @@ -40,8 +40,8 @@ async function run () { process.exit(1) } - const { body } = await client.msearch({ - body: [ + const result = await client.msearch({ + searches: [ { index: 'game-of-thrones' }, { query: { match: { character: 'Daenerys' } } }, @@ -50,7 +50,7 @@ async function run () { ] }) - console.log(body.responses) + console.log(result.responses) } run().catch(console.log) diff --git a/docs/examples/proxy/api/autocomplete.js b/docs/examples/proxy/api/autocomplete.js index e103a6eaf..fb18298cf 100644 --- a/docs/examples/proxy/api/autocomplete.js +++ b/docs/examples/proxy/api/autocomplete.js @@ -70,17 +70,15 @@ module.exports = async (req, res) => { // expose you to the risk that a malicious user // could overload your cluster by crafting // expensive queries. - body: { - _source: ['id', 'url', 'name'], // the fields you want to show in the autocompletion - size: 0, - // https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html - suggest: { - suggestions: { - prefix: req.query.q, - completion: { - field: 'suggest', - size: 5 - } + _source: ['id', 'url', 'name'], // the fields you want to show in the autocompletion + size: 0, + // https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html + suggest: { + suggestions: { + prefix: req.query.q, + completion: { + field: 'suggest', + size: 5 } } } @@ -93,7 +91,7 @@ module.exports = async (req, res) => { // It might be useful to configure http control caching headers // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control // res.setHeader('stale-while-revalidate', '30') - res.json(response.body) + res.json(response) } catch (err) { res.status(err.statusCode || 500) res.json({ diff --git a/docs/examples/proxy/api/delete.js b/docs/examples/proxy/api/delete.js index 75d4c9a00..b76108428 100644 --- a/docs/examples/proxy/api/delete.js +++ b/docs/examples/proxy/api/delete.js @@ -62,7 +62,7 @@ module.exports = async (req, res) => { } }) - res.json(response.body) + res.json(response) } catch (err) { res.status(err.statusCode || 500) res.json({ diff --git a/docs/examples/proxy/api/index.js b/docs/examples/proxy/api/index.js index a75affe5e..901139713 100644 --- a/docs/examples/proxy/api/index.js +++ b/docs/examples/proxy/api/index.js @@ -56,11 +56,12 @@ module.exports = async (req, res) => { const response = await client.index({ index: INDEX, id: req.query.id, - body: req.body + document: req.body }, { headers: { Authorization: `ApiKey ${token}` - } + }, + meta: true }) res.status(response.statusCode) diff --git a/docs/examples/proxy/api/search.js b/docs/examples/proxy/api/search.js index da8896f58..8659e08f4 100644 --- a/docs/examples/proxy/api/search.js +++ b/docs/examples/proxy/api/search.js @@ -60,10 +60,8 @@ module.exports = async (req, res) => { // expose you to the risk that a malicious user // could overload your cluster by crafting // expensive queries. - body: { - query: { - match: { field: req.body.text } - } + query: { + match: { field: req.body.text } } }, { headers: { @@ -74,7 +72,7 @@ module.exports = async (req, res) => { // It might be useful to configure http control caching headers // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control // res.setHeader('stale-while-revalidate', '30') - res.json(response.body) + res.json(response) } catch (err) { res.status(err.statusCode || 500) res.json({ diff --git a/docs/examples/proxy/package.json b/docs/examples/proxy/package.json index 34af9b020..bfe19ae84 100644 --- a/docs/examples/proxy/package.json +++ b/docs/examples/proxy/package.json @@ -11,7 +11,7 @@ "author": "Tomas Della Vedova", "license": "Apache-2.0", "dependencies": { - "@elastic/elasticsearch": "^7.10.0" + "@elastic/elasticsearch": "^8.0.0" }, "devDependencies": { "standard": "^16.0.3" diff --git a/docs/examples/proxy/utils/prepare-elasticsearch.js b/docs/examples/proxy/utils/prepare-elasticsearch.js index 257837f51..bf833f0c2 100644 --- a/docs/examples/proxy/utils/prepare-elasticsearch.js +++ b/docs/examples/proxy/utils/prepare-elasticsearch.js @@ -43,21 +43,19 @@ async function generateApiKeys (opts) { } }) - const { body } = await client.security.createApiKey({ - body: { - name: 'elasticsearch-proxy', - role_descriptors: { - 'elasticsearch-proxy-users': { - index: [{ - names: indexNames, - privileges - }] - } + const result = await client.security.createApiKey({ + name: 'elasticsearch-proxy', + role_descriptors: { + 'elasticsearch-proxy-users': { + index: [{ + names: indexNames, + privileges + }] } } }) - return Buffer.from(`${body.id}:${body.api_key}`).toString('base64') + return Buffer.from(`${result.id}:${result.api_key}`).toString('base64') } generateApiKeys() diff --git a/docs/examples/reindex.asciidoc b/docs/examples/reindex.asciidoc index aa722707f..984e21c99 100644 --- a/docs/examples/reindex.asciidoc +++ b/docs/examples/reindex.asciidoc @@ -20,7 +20,7 @@ const client = new Client({ node: 'http://localhost:9200' }) async function run () { await client.index({ index: 'game-of-thrones', - body: { + document: { character: 'Ned Stark', quote: 'Winter is coming.', house: 'stark' @@ -29,7 +29,7 @@ async function run () { await client.index({ index: 'game-of-thrones', - body: { + document: { character: 'Arya Stark', quote: 'A girl is Arya Stark of Winterfell. And I\'m going home.', house: 'stark' @@ -39,7 +39,7 @@ async function run () { await client.index({ index: 'game-of-thrones', refresh: true, - body: { + document: { character: 'Tyrion Lannister', quote: 'A Lannister always pays his debts.', house: 'lannister' @@ -47,33 +47,29 @@ async function run () { }) await client.reindex({ - waitForCompletion: true, + wait_for_completion: true, refresh: true, - body: { - source: { - index: 'game-of-thrones', - query: { - match: { character: 'stark' } - } - }, - dest: { - index: 'stark-index' - }, - script: { - lang: 'painless', - source: 'ctx._source.remove("house")' + source: { + index: 'game-of-thrones', + query: { + match: { character: 'stark' } } + }, + dest: { + index: 'stark-index' + }, + script: { + lang: 'painless', + source: 'ctx._source.remove("house")' } }) - const { body } = await client.search({ + const result = await client.search({ index: 'stark-index', - body: { - query: { match_all: {} } - } + query: { match_all: {} } }) - console.log(body.hits.hits) + console.log(result.hits.hits) } run().catch(console.log) diff --git a/docs/examples/scroll.asciidoc b/docs/examples/scroll.asciidoc index c46493e73..90e6e6524 100644 --- a/docs/examples/scroll.asciidoc +++ b/docs/examples/scroll.asciidoc @@ -33,12 +33,12 @@ async function run () { const responseQueue = [] // Let's index some data! - const { body: bulkResponse } = await client.bulk({ + const bulkResponse = await client.bulk({ // here we are forcing an index refresh, // otherwise we will not get any result // in the consequent search refresh: true, - body: [ + operations: [ // operation to perform { index: { _index: 'game-of-thrones' } }, // the document to index @@ -76,17 +76,15 @@ async function run () { size: 1, // filter the source to only include the quote field _source: ['quote'], - body: { - query: { - match_all: {} - } + query: { + match_all: {} } }) responseQueue.push(response) while (responseQueue.length) { - const { body } = responseQueue.shift() + const body = responseQueue.shift() // collect the titles from this response body.hits.hits.forEach(function (hit) { @@ -127,7 +125,7 @@ async function * scrollSearch (params) { let response = await client.search(params) while (true) { - const sourceHits = response.body.hits.hits + const sourceHits = response.hits.hits if (sourceHits.length === 0) { break @@ -137,12 +135,12 @@ async function * scrollSearch (params) { yield hit } - if (!response.body._scroll_id) { + if (!response._scroll_id) { break } response = await client.scroll({ - scrollId: response.body._scroll_id, + scrollId: response._scroll_id, scroll: params.scroll }) } @@ -151,7 +149,7 @@ async function * scrollSearch (params) { async function run () { await client.bulk({ refresh: true, - body: [ + operations: [ { index: { _index: 'game-of-thrones' } }, { character: 'Ned Stark', @@ -177,10 +175,8 @@ async function run () { scroll: '30s', size: 1, _source: ['quote'], - body: { - query: { - match_all: {} - } + query: { + match_all: {} } } diff --git a/docs/examples/search.asciidoc b/docs/examples/search.asciidoc index fb4fe4d2b..2cf5b3c50 100644 --- a/docs/examples/search.asciidoc +++ b/docs/examples/search.asciidoc @@ -18,7 +18,7 @@ async function run () { // Let's start by indexing some data await client.index({ index: 'game-of-thrones', - body: { + document: { character: 'Ned Stark', quote: 'Winter is coming.' } @@ -26,7 +26,7 @@ async function run () { await client.index({ index: 'game-of-thrones', - body: { + document: { character: 'Daenerys Targaryen', quote: 'I am the blood of the dragon.' } @@ -38,25 +38,23 @@ async function run () { // otherwise we will not get any result // in the consequent search refresh: true, - body: { + document: { character: 'Tyrion Lannister', quote: 'A mind needs books like a sword needs a whetstone.' } }) // Let's search! - const { body } = await client.search({ + const result = await client.search({ index: 'game-of-thrones', - body: { - query: { - match: { - quote: 'winter' - } + query: { + match: { + quote: 'winter' } } }) - console.log(body.hits.hits) + console.log(result.hits.hits) } run().catch(console.log) diff --git a/docs/examples/sql.query.asciidoc b/docs/examples/sql.query.asciidoc index da5ff8b12..00505d2fd 100644 --- a/docs/examples/sql.query.asciidoc +++ b/docs/examples/sql.query.asciidoc @@ -22,7 +22,7 @@ const client = new Client({ node: 'http://localhost:9200' }) async function run () { await client.index({ index: 'game-of-thrones', - body: { + document: { character: 'Ned Stark', quote: 'Winter is coming.', house: 'stark' @@ -31,7 +31,7 @@ async function run () { await client.index({ index: 'game-of-thrones', - body: { + document: { character: 'Arya Stark', quote: 'A girl is Arya Stark of Winterfell. And I\'m going home.', house: 'stark' @@ -41,25 +41,23 @@ async function run () { await client.index({ index: 'game-of-thrones', refresh: true, - body: { + document: { character: 'Tyrion Lannister', quote: 'A Lannister always pays his debts.', house: 'lannister' } }) - const { body } = await client.sql.query({ - body: { - query: "SELECT * FROM \"game-of-thrones\" WHERE house='stark'" - } + const result = await client.sql.query({ + query: "SELECT * FROM \"game-of-thrones\" WHERE house='stark'" }) - console.log(body) + console.log(result) - const data = body.rows.map(row => { + const data = result.rows.map(row => { const obj = {} for (let i = 0; i < row.length; i++) { - obj[body.columns[i].name] = row[i] + obj[result.columns[i].name] = row[i] } return obj }) diff --git a/docs/examples/suggest.asciidoc b/docs/examples/suggest.asciidoc index b03ece4e1..d4448a1a4 100644 --- a/docs/examples/suggest.asciidoc +++ b/docs/examples/suggest.asciidoc @@ -15,9 +15,9 @@ const { Client } = require('@elastic/elasticsearch') const client = new Client({ node: 'http://localhost:9200' }) async function run () { - const { body: bulkResponse } = await client.bulk({ + const bulkResponse = await client.bulk({ refresh: true, - body: [ + operations: [ { index: { _index: 'game-of-thrones' } }, { character: 'Ned Stark', @@ -43,22 +43,20 @@ async function run () { process.exit(1) } - const { body } = await client.search({ + const result = await client.search({ index: 'game-of-thrones', - body: { - query: { - match: { quote: 'witner' } - }, - suggest: { - gotsuggest: { - text: 'witner', - term: { field: 'quote' } - } + query: { + match: { quote: 'winter' } + }, + suggest: { + gotsuggest: { + text: 'winter', + term: { field: 'quote' } } } }) - console.log(body) + console.log(result) } run().catch(console.log) diff --git a/docs/examples/transport.request.asciidoc b/docs/examples/transport.request.asciidoc index d74c6c68d..86482046f 100644 --- a/docs/examples/transport.request.asciidoc +++ b/docs/examples/transport.request.asciidoc @@ -23,9 +23,9 @@ const { Client } = require('@elastic/elasticsearch') const client = new Client({ node: 'http://localhost:9200' }) async function run () { - const { body: bulkResponse } = await client.bulk({ + const bulkResponse = await client.bulk({ refresh: true, - body: [ + operations: [ { index: { _index: 'game-of-thrones' } }, { character: 'Ned Stark', @@ -51,7 +51,7 @@ async function run () { process.exit(1) } - const { body } = await client.transport.request({ + const response = await client.transport.request({ method: 'POST', path: '/game-of-thrones/_search', body: { @@ -64,7 +64,7 @@ async function run () { querystring: {} }) - console.log(body) + console.log(response) } run().catch(console.log) diff --git a/docs/examples/typescript.asciidoc b/docs/examples/typescript.asciidoc deleted file mode 100644 index 2d39ed2ac..000000000 --- a/docs/examples/typescript.asciidoc +++ /dev/null @@ -1,72 +0,0 @@ -[[typescript_examples]] -=== Typescript - -The client offers a first-class support for TypeScript, since it ships the type -definitions for every exposed API. - -NOTE: If you are using TypeScript you will be required to use _snake_case_ style -to define the API parameters instead of _camelCase_. - -[source,ts] ----- -'use strict' - -import { Client, ApiResponse, RequestParams } from '@elastic/elasticsearch' -const client = new Client({ node: 'http://localhost:9200' }) - -async function run (): void { - // Let's start by indexing some data - const doc1: RequestParams.Index = { - index: 'game-of-thrones', - body: { - character: 'Ned Stark', - quote: 'Winter is coming.' - } - } - await client.index(doc1) - - const doc2: RequestParams.Index = { - index: 'game-of-thrones', - body: { - character: 'Daenerys Targaryen', - quote: 'I am the blood of the dragon.' - } - } - await client.index(doc2) - - const doc3: RequestParams.Index = { - index: 'game-of-thrones', - // here we are forcing an index refresh, - // otherwise we will not get any result - // in the consequent search - refresh: true, - body: { - character: 'Tyrion Lannister', - quote: 'A mind needs books like a sword needs a whetstone.' - } - } - await client.index(doc3) - - // Let's search! - const params: RequestParams.Search = { - index: 'game-of-thrones', - body: { - query: { - match: { - quote: 'winter' - } - } - } - } - client - .search(params) - .then((result: ApiResponse) => { - console.log(result.body.hits.hits) - }) - .catch((err: Error) => { - console.log(err) - }) -} - -run() ----- \ No newline at end of file diff --git a/docs/examples/update.asciidoc b/docs/examples/update.asciidoc index 342bf2348..784a7d6d8 100644 --- a/docs/examples/update.asciidoc +++ b/docs/examples/update.asciidoc @@ -16,7 +16,7 @@ async function run () { await client.index({ index: 'game-of-thrones', id: '1', - body: { + document: { character: 'Ned Stark', quote: 'Winter is coming.', times: 0 @@ -26,23 +26,21 @@ async function run () { await client.update({ index: 'game-of-thrones', id: '1', - body: { - script: { - lang: 'painless', - source: 'ctx._source.times++' - // you can also use parameters - // source: 'ctx._source.times += params.count', - // params: { count: 1 } - } + script: { + lang: 'painless', + source: 'ctx._source.times++' + // you can also use parameters + // source: 'ctx._source.times += params.count', + // params: { count: 1 } } }) - const { body } = await client.get({ + const document = await client.get({ index: 'game-of-thrones', id: '1' }) - console.log(body) + console.log(document) } run().catch(console.log) @@ -62,7 +60,7 @@ async function run () { await client.index({ index: 'game-of-thrones', id: '1', - body: { + document: { character: 'Ned Stark', quote: 'Winter is coming.', isAlive: true @@ -72,19 +70,17 @@ async function run () { await client.update({ index: 'game-of-thrones', id: '1', - body: { - doc: { - isAlive: false - } + doc: { + isAlive: false } }) - const { body } = await client.get({ + const document = await client.get({ index: 'game-of-thrones', id: '1' }) - console.log(body) + console.log(document) } run().catch(console.log) diff --git a/docs/examples/update_by_query.asciidoc b/docs/examples/update_by_query.asciidoc index 85e4f3ff9..fdb198aec 100644 --- a/docs/examples/update_by_query.asciidoc +++ b/docs/examples/update_by_query.asciidoc @@ -15,7 +15,7 @@ const client = new Client({ node: 'http://localhost:9200' }) async function run () { await client.index({ index: 'game-of-thrones', - body: { + document: { character: 'Ned Stark', quote: 'Winter is coming.' } @@ -24,7 +24,7 @@ async function run () { await client.index({ index: 'game-of-thrones', refresh: true, - body: { + document: { character: 'Arya Stark', quote: 'A girl is Arya Stark of Winterfell. And I\'m going home.' } @@ -33,27 +33,23 @@ async function run () { await client.updateByQuery({ index: 'game-of-thrones', refresh: true, - body: { - script: { - lang: 'painless', - source: 'ctx._source["house"] = "stark"' - }, - query: { - match: { - character: 'stark' - } + script: { + lang: 'painless', + source: 'ctx._source["house"] = "stark"' + }, + query: { + match: { + character: 'stark' } } }) - const { body } = await client.search({ + const result = await client.search({ index: 'game-of-thrones', - body: { - query: { match_all: {} } - } + query: { match_all: {} } }) - console.log(body.hits.hits) + console.log(result.hits.hits) } run().catch(console.log) diff --git a/docs/extend.asciidoc b/docs/extend.asciidoc deleted file mode 100644 index 069cacd86..000000000 --- a/docs/extend.asciidoc +++ /dev/null @@ -1,72 +0,0 @@ -[[extend]] -=== Extend the client - -Sometimes you need to reuse the same logic, or you want to build a custom API to -allow you simplify your code. The easiest way to achieve that is by extending -the client. - -NOTE: If you want to override existing methods, you should specify the -`{ force: true }` option. - -[source,js] ----- -const { Client } = require('@elastic/elasticsearch') -const client = new Client({ node: 'http://localhost:9200' }) - -client.extend('supersearch', ({ makeRequest, ConfigurationError }) => { - return function supersearch (params, options) { - const { - body, - index, - method, - ...querystring - } = params - - // params validation - if (body == null) { - throw new ConfigurationError('Missing required parameter: body') - } - - // build request object - const request = { - method: method || 'POST', - path: `/${encodeURIComponent(index)}/_search_`, - body, - querystring - } - - // build request options object - const requestOptions = { - ignore: options.ignore || null, - requestTimeout: options.requestTimeout || null, - maxRetries: options.maxRetries || null, - asStream: options.asStream || false, - headers: options.headers || null - } - - return makeRequest(request, requestOptions) - } -}) - -client.extend('utility.index', ({ makeRequest }) => { - return function _index (params, options) { - // your code - } -}) - -client.extend('utility.delete', ({ makeRequest }) => { - return function _delete (params, options) { - // your code - } -}) - -client.extend('indices.delete', { force: true }, ({ makeRequest }) => { - return function _delete (params, options) { - // your code - } -}) - -client.supersearch(...) -client.utility.index(...) -client.utility.delete(...) ----- \ No newline at end of file diff --git a/docs/helpers.asciidoc b/docs/helpers.asciidoc index 71dd9de15..f83d29144 100644 --- a/docs/helpers.asciidoc +++ b/docs/helpers.asciidoc @@ -341,23 +341,12 @@ const { Client } = require('@elastic/elasticsearch') const client = new Client({ node: 'http://localhost:9200' }) const m = client.helpers.msearch() -// promise style API m.search( { index: 'stackoverflow' }, { query: { match: { title: 'javascript' } } } ) .then(result => console.log(result.body)) // or result.documents .catch(err => console.error(err)) - -// callback style API -m.search( - { index: 'stackoverflow' }, - { query: { match: { title: 'ruby' } } }, - (err, result) => { - if (err) console.error(err) - console.log(result.body)) // or result.documents - } -) ---- To create a new instance of the multi search (msearch) helper, you should access @@ -474,11 +463,9 @@ the query string. ---- const documents = await client.helpers.search({ index: 'stackoverflow', - body: { - query: { - match: { - title: 'javascript' - } + query: { + match: { + title: 'javascript' } } }) @@ -505,11 +492,9 @@ the `429` error and uses the `maxRetries` option of the client. ---- const scrollSearch = client.helpers.scrollSearch({ index: 'stackoverflow', - body: { - query: { - match: { - title: 'javascript' - } + query: { + match: { + title: 'javascript' } } }) @@ -564,11 +549,9 @@ automatically adds `filter_path=hits.hits._source` to the query string. ---- const scrollSearch = client.helpers.scrollDocuments({ index: 'stackoverflow', - body: { - query: { - match: { - title: 'javascript' - } + query: { + match: { + title: 'javascript' } } }) diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 959296357..fd8ab0484 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -10,7 +10,6 @@ include::configuration.asciidoc[] include::basic-config.asciidoc[] include::advanced-config.asciidoc[] include::child.asciidoc[] -include::extend.asciidoc[] include::testing.asciidoc[] include::integrations.asciidoc[] include::observability.asciidoc[] diff --git a/docs/installation.asciidoc b/docs/installation.asciidoc index 0d44a1518..bd8684aba 100644 --- a/docs/installation.asciidoc +++ b/docs/installation.asciidoc @@ -56,6 +56,10 @@ of `^7.10.0`). |`10.x` |April 2021 |`7.12` (mid 2021) + +|`12.x` +|April 2022 +|`8.2` (early 2022) |=== [discrete] @@ -70,8 +74,8 @@ Elasticsearch language clients are only backwards compatible with default distri |{es} Version |Client Version -|`main` -|`main` +|`8.x` +|`8.x` |`7.x` |`7.x` diff --git a/docs/introduction.asciidoc b/docs/introduction.asciidoc index 6cb9df2bc..5d8ba3cbe 100644 --- a/docs/introduction.asciidoc +++ b/docs/introduction.asciidoc @@ -4,9 +4,6 @@ This is the official Node.js client for {es}. This page gives a quick overview about the features of the client. -Refer to <> for breaking changes coming from the old -client. - [discrete] === Features @@ -23,59 +20,6 @@ client. [discrete] === Quick start -First of all, require, then initialize the client: - -[source,js] ----- -const { Client } = require('@elastic/elasticsearch') -const client = new Client({ node: 'http://localhost:9200' }) ----- - - -You can use both the callback API and the promise API, both behave the same way. - -[source,js] ----- -// promise API -const result = await client.search({ - index: 'my-index', - body: { - query: { - match: { hello: 'world' } - } - } -}) - -// callback API -client.search({ - index: 'my-index', - body: { - query: { - match: { hello: 'world' } - } - } -}, (err, result) => { - if (err) console.log(err) -}) ----- - - -The returned value of **every** API call is formed as follows: - -[source,ts] ----- -{ - body: object | boolean - statusCode: number - headers: object - warnings: [string] - meta: object -} ----- - - -Let's see a complete example! - [source,js] ---- 'use strict' @@ -87,8 +31,7 @@ async function run () { // Let's start by indexing some data await client.index({ index: 'game-of-thrones', - // type: '_doc', // uncomment this line if you are using {es} ≤ 6 - body: { + document: { character: 'Ned Stark', quote: 'Winter is coming.' } @@ -96,8 +39,7 @@ async function run () { await client.index({ index: 'game-of-thrones', - // type: '_doc', // uncomment this line if you are using {es} ≤ 6 - body: { + document: { character: 'Daenerys Targaryen', quote: 'I am the blood of the dragon.' } @@ -105,29 +47,25 @@ async function run () { await client.index({ index: 'game-of-thrones', - // type: '_doc', // uncomment this line if you are using {es} ≤ 6 - body: { + document: { character: 'Tyrion Lannister', quote: 'A mind needs books like a sword needs a whetstone.' } }) - // We need to force an index refresh at this point, otherwise we will not + // here we are forcing an index refresh, otherwise we will not // get any result in the consequent search await client.indices.refresh({ index: 'game-of-thrones' }) // Let's search! - const { body } = await client.search({ + const result= await client.search({ index: 'game-of-thrones', - // type: '_doc', // uncomment this line if you are using {es} ≤ 6 - body: { - query: { - match: { quote: 'winter' } - } + query: { + match: { quote: 'winter' } } }) - console.log(body.hits.hits) + console.log(result.hits.hits) } run().catch(console.log) @@ -181,20 +119,17 @@ const { Client: Client7 } = require('es7') const client6 = new Client6({ node: 'http://localhost:9200' }) const client7 = new Client7({ node: 'http://localhost:9201' }) -client6.info(console.log) -client7.info(console.log) +client6.info().then(console.log, console.log) +client7.info().then(console.log, console.log) ---- Finally, if you want to install the client for the next version of {es} (the one -that lives in the {es} master branch), use the following command: +that lives in the {es} main branch), use the following command: [source,sh] ---- -npm install esmaster@github:elastic/elasticsearch-js +npm install esmain@github:elastic/elasticsearch-js ---- -WARNING: This command installs the master branch of the client which is not -considered stable. - - -include::breaking-changes.asciidoc[] \ No newline at end of file +WARNING: This command installs the main branch of the client which is not +considered stable. \ No newline at end of file diff --git a/docs/observability.asciidoc b/docs/observability.asciidoc index 66c45fb42..44307f68b 100644 --- a/docs/observability.asciidoc +++ b/docs/observability.asciidoc @@ -2,7 +2,7 @@ === Observability The client does not provide a default logger, but instead it offers an event -emitter interfaces to hook into internal events, such as `request` and +emitter interface to hook into internal events, such as `request` and `response`. Correlating those events can be hard, especially if your applications have a @@ -36,7 +36,7 @@ const logger = require('my-logger')() const { Client } = require('@elastic/elasticsearch') const client = new Client({ node: 'http://localhost:9200' }) -client.on('response', (err, result) => { +client.diagnostic.on('response', (err, result) => { if (err) { logger.error(err) } else { @@ -53,7 +53,7 @@ The client emits the following events: a|Emitted before starting serialization and compression. If you want to measure this phase duration, you should measure the time elapsed between this event and `request`. [source,js] ---- -client.on('serialization', (err, result) => { +client.diagnostic.on('serialization', (err, result) => { console.log(err, result) }) ---- @@ -62,7 +62,7 @@ client.on('serialization', (err, result) => { a|Emitted before sending the actual request to {es} _(emitted multiple times in case of retries)_. [source,js] ---- -client.on('request', (err, result) => { +client.diagnostic.on('request', (err, result) => { console.log(err, result) }) ---- @@ -71,7 +71,7 @@ client.on('request', (err, result) => { a|Emitted before starting deserialization and decompression. If you want to measure this phase duration, you should measure the time elapsed between this event and `response`. _(This event might not be emitted in certain situations)_. [source,js] ---- -client.on('deserialization', (err, result) => { +client.diagnostic.on('deserialization', (err, result) => { console.log(err, result) }) ---- @@ -80,7 +80,7 @@ client.on('deserialization', (err, result) => { a|Emitted once {es} response has been received and parsed. [source,js] ---- -client.on('response', (err, result) => { +client.diagnostic.on('response', (err, result) => { console.log(err, result) }) ---- @@ -89,7 +89,7 @@ client.on('response', (err, result) => { a|Emitted when the client ends a sniffing request. [source,js] ---- -client.on('sniff', (err, result) => { +client.diagnostic.on('sniff', (err, result) => { console.log(err, result) }) ---- @@ -98,7 +98,7 @@ client.on('sniff', (err, result) => { a|Emitted if the client is able to resurrect a dead node. [source,js] ---- -client.on('resurrect', (err, result) => { +client.diagnostic.on('resurrect', (err, result) => { console.log(err, result) }) ---- @@ -185,14 +185,14 @@ handle this problem. const { Client } = require('@elastic/elasticsearch') const client = new Client({ node: 'http://localhost:9200' }) -client.on('request', (err, result) => { +client.diagnostic.on('request', (err, result) => { const { id } = result.meta.request if (err) { console.log({ error: err, reqId: id }) } }) -client.on('response', (err, result) => { +client.diagnostic.on('response', (err, result) => { const { id } = result.meta.request if (err) { console.log({ error: err, reqId: id }) @@ -201,10 +201,8 @@ client.on('response', (err, result) => { client.search({ index: 'my-index', - body: { foo: 'bar' } -}, (err, result) => { - if (err) console.log(err) -}) + query: { match_all: {} } +}).then(console.log, console.log) ---- @@ -232,12 +230,10 @@ You can also specify a custom id per request: ---- client.search({ index: 'my-index', - body: { foo: 'bar' } + query: { match_all: {} } }, { id: 'custom-id' -}, (err, result) => { - if (err) console.log(err) -}) +}).then(console.log, console.log) ---- @@ -252,7 +248,7 @@ can do that via the `context` option of a request: const { Client } = require('@elastic/elasticsearch') const client = new Client({ node: 'http://localhost:9200' }) -client.on('request', (err, result) => { +client.diagnostic.on('request', (err, result) => { const { id } = result.meta.request const { context } = result.meta if (err) { @@ -260,7 +256,7 @@ client.on('request', (err, result) => { } }) -client.on('response', (err, result) => { +client.diagnostic.on('response', (err, result) => { const { id } = result.meta.request const { winter } = result.meta.context if (err) { @@ -270,12 +266,10 @@ client.on('response', (err, result) => { client.search({ index: 'my-index', - body: { foo: 'bar' } + query: { match_all: {} } }, { context: { winter: 'is coming' } -}, (err, result) => { - if (err) console.log(err) -}) +}).then(console.log, console.log) ---- The context object can also be configured as a global option in the client @@ -290,7 +284,7 @@ const client = new Client({ context: { winter: 'is coming' } }) -client.on('request', (err, result) => { +client.diagnostic.on('request', (err, result) => { const { id } = result.meta.request const { context } = result.meta if (err) { @@ -298,7 +292,7 @@ client.on('request', (err, result) => { } }) -client.on('response', (err, result) => { +client.diagnostic.on('response', (err, result) => { const { id } = result.meta.request const { winter } = result.meta.context if (err) { @@ -308,12 +302,10 @@ client.on('response', (err, result) => { client.search({ index: 'my-index', - body: { foo: 'bar' } + query: { match_all: {} } }, { context: { winter: 'has come' } -}, (err, result) => { - if (err) console.log(err) -}) +}).then(console.log, console.log) ---- @@ -339,7 +331,7 @@ const child = client.child({ console.log(client.name, child.name) -client.on('request', (err, result) => { +client.diagnostic.on('request', (err, result) => { const { id } = result.meta.request const { name } = result.meta if (err) { @@ -347,7 +339,7 @@ client.on('request', (err, result) => { } }) -client.on('response', (err, result) => { +client.diagnostic.on('response', (err, result) => { const { id } = result.meta.request const { name } = result.meta if (err) { @@ -357,17 +349,13 @@ client.on('response', (err, result) => { client.search({ index: 'my-index', - body: { foo: 'bar' } -}, (err, result) => { - if (err) console.log(err) -}) + query: { match_all: {} } +}).then(console.log, console.log) child.search({ index: 'my-index', - body: { foo: 'bar' } -}, (err, result) => { - if (err) console.log(err) -}) + query: { match_all: {} } +}).then(console.log, console.log) ---- @@ -397,9 +385,7 @@ client.search({ body: { foo: 'bar' } }, { opaqueId: 'my-search' -}, (err, result) => { - if (err) console.log(err) -}) +}).then(console.log, console.log) ---- Sometimes it may be useful to prefix all the `X-Opaque-Id` headers with a @@ -421,8 +407,6 @@ client.search({ body: { foo: 'bar' } }, { opaqueId: 'my-search' -}, (err, result) => { - if (err) console.log(err) -}) +}).then(console.log, console.log) ---- diff --git a/docs/testing.asciidoc b/docs/testing.asciidoc index af9fcf25f..34778ba06 100644 --- a/docs/testing.asciidoc +++ b/docs/testing.asciidoc @@ -72,7 +72,7 @@ mock.add({ return { status: 'ok' } }) -client.info(console.log) +client.info().then(console.log, console.log) ---- As you can see it works closely with the client itself, once you have created a @@ -129,8 +129,8 @@ mock.add({ return { count: 42 } }) -client.count({ index: 'foo' }, console.log) // => { count: 42 } -client.count({ index: 'bar' }, console.log) // => { count: 42 } +client.count({ index: 'foo' }).then(console.log, console.log) // => { count: 42 } +client.count({ index: 'bar' }).then(console.log, console.log) // => { count: 42 } ---- And wildcards are supported as well. diff --git a/docs/typescript.asciidoc b/docs/typescript.asciidoc index 13da1b10f..eace26e63 100644 --- a/docs/typescript.asciidoc +++ b/docs/typescript.asciidoc @@ -4,274 +4,73 @@ The client offers a first-class support for TypeScript, shipping a complete set of type definitions of Elasticsearch's API surface. - -NOTE: If you are using TypeScript you need to use _snake_case_ style to define -the API parameters instead of _camelCase_. - -Currently the client exposes two type definitions, the legacy one, which is the default -and the new one, which will be the default in the next major. -We strongly recommend to migrate to the new one as soon as possible, as the new types -are offering a vastly improved developer experience and guarantee you that your code -will always be in sync with the latest Elasticsearch features. - -[discrete] -==== New type definitions - -The new type definition is more advanced compared to the legacy one. In the legacy -type definitions you were expected to configure via generics both request and response -bodies. The new type definitions comes with a complete type definition for every -Elasticsearch endpoint. - -For example: - -[source,ts] ----- -// legacy definitions -const response = await client.search, SearchBody>({ - index: 'test', - body: { - query: { - match: { foo: 'bar' } - } - } -}) - -// new definitions -const response = await client.search({ - index: 'test', - body: { - query: { - match: { foo: 'bar' } - } - } -}) ----- - The types are not 100% complete yet. Some APIs are missing (the newest ones, e.g. EQL), and others may contain some errors, but we are continuously pushing fixes & improvements. [discrete] -==== Request & Response types - -Once you migrate to the new types, those are automatically integrated into the Elasticsearch client, you will get them out of the box. -If everything works, meaning that you won’t get compiler errors, you are good to go! -The types are already correct, and there is nothing more to do. - -If a type is incorrect, you should add a comment `// @ts-expect-error @elastic/elasticsearch` -telling TypeScript that you are aware of the warning and you would like to temporarily suppress it. -In this way, your code will compile until the type is fixed, and when it happens, you’ll only need to remove the -`// @ts-expect-error @elastic/elasticsearch` comment (TypeScript will let you know when it is time). -Finally, if the type you need is missing, you’ll see that the client method returns (or defines as a parameter) -a `TODO` type, which accepts any object. - -Open an issue in the client repository letting us know if you encounter any problem! - -If needed you can import the request and response types. - -[source,ts] ----- -import { Client, estypes } from '@elastic/elasticsearch' -import type { Client as NewTypes } from '@elastic/elasticsearch/api/new' - -// @ts-expect-error @elastic/elasticsearch -const client: NewTypes = new Client({ - node: 'http://localhost:9200' -}) - -interface Source { - foo: string -} - -const request: estypes.IndexRequest = { - index: 'test', - body: { foo: 'bar' } -} - -await client.index(request) ----- - -[discrete] -===== How to migrate to the new type definitions - -Since the new type definitions can be considered a breaking change we couldn't add the directly to the client. -Following you will find a snippet that shows you how to override the default types with the new ones. +==== Example [source,ts] ---- import { Client } from '@elastic/elasticsearch' -import type { Client as NewTypes } from '@elastic/elasticsearch/api/new' - -// @ts-expect-error @elastic/elasticsearch -const client: NewTypes = new Client({ - node: 'http://localhost:9200' -}) - -interface Source { - foo: string -} - -// try the new code completion when building a query! -const response = await client.search({ - index: 'test', - body: { - query: { - match_all: {} - } - } -}) - -// try the new code completion when traversing a response! -const results = response.body.hits.hits.map(hit => hit._source) -// results type will be `Source[]` -console.log(results) ----- - -[discrete] -==== Legacy type definitions - -By default event API uses -https://www.typescriptlang.org/docs/handbook/generics.html[generics] to specify -the requests and response bodies and the `meta.context`. Currently, we can't -provide those definitions, but we are working to improve this situation. - -You can find a partial definition of the request types by importing -`RequestParams`, which is used by default in the client and accepts a body (when -needed) as a generic to provide a better specification. - -The body defaults to `RequestBody` and `RequestNDBody`, which are defined as -follows: - -[source,ts] ----- -type RequestBody> = T | string | Buffer | ReadableStream -type RequestNDBody[]> = T | string | string[] | Buffer | ReadableStream ----- - -You can specify the response and request body in each API as follows: - -[source,ts] ----- -const response = await client.search({ - index: 'test', - body: { - query: { - match: { foo: 'bar' } - } - } -}) - -console.log(response.body) ----- - -You don't have to specify all the generics, but the order must be respected. - - -[discrete] -===== A complete example - -[source,ts] ----- -import { - Client, - // Object that contains the type definitions of every API method - RequestParams, - // Interface of the generic API response - ApiResponse, -} from '@elastic/elasticsearch' const client = new Client({ node: 'http://localhost:9200' }) -// Define the type of the body for the Search request -interface SearchBody { - query: { - match: { foo: string } - } -} - -// Complete definition of the Search response -interface ShardsResponse { - total: number; - successful: number; - failed: number; - skipped: number; -} - -interface Explanation { - value: number; - description: string; - details: Explanation[]; -} - -interface SearchResponse { - took: number; - timed_out: boolean; - _scroll_id?: string; - _shards: ShardsResponse; - hits: { - total: number; - max_score: number; - hits: Array<{ - _index: string; - _type: string; - _id: string; - _score: number; - _source: T; - _version?: number; - _explanation?: Explanation; - fields?: any; - highlight?: any; - inner_hits?: any; - matched_queries?: string[]; - sort?: string[]; - }>; - }; - aggregations?: any; -} - -// Define the interface of the source object -interface Source { - foo: string +interface Document { + character: string + quote: string } async function run () { - // All of the examples below are valid code, by default, - // the request body will be `RequestBody` and response will be `Record`. - let response = await client.search({ - index: 'test', - body: { - query: { - match: { foo: 'bar' } - } + // Let's start by indexing some data + await client.index({ + index: 'game-of-thrones', + document: { + character: 'Ned Stark', + quote: 'Winter is coming.' } }) - // body here is `ResponseBody` - console.log(response.body) - // The first generic is the response body - response = await client.search>({ - index: 'test', - // Here the body must follow the `RequestBody` interface - body: { - query: { - match: { foo: 'bar' } - } + await client.index({ + index: 'game-of-thrones', + document: { + character: 'Daenerys Targaryen', + quote: 'I am the blood of the dragon.' } }) - // body here is `SearchResponse` - console.log(response.body) - response = await client.search, SearchBody>({ - index: 'test', - // Here the body must follow the `SearchBody` interface - body: { - query: { - match: { foo: 'bar' } - } + await client.index({ + index: 'game-of-thrones', + document: { + character: 'Tyrion Lannister', + quote: 'A mind needs books like a sword needs a whetstone.' } }) - // body here is `SearchResponse` - console.log(response.body) + + // here we are forcing an index refresh, otherwise we will not + // get any result in the consequent search + await client.indices.refresh({ index: 'game-of-thrones' }) + + // Let's search! + const result= await client.search({ + index: 'game-of-thrones', + query: { + match: { quote: 'winter' } + } + }) + + console.log(result.hits.hits) } run().catch(console.log) ---- + +[discrete] +==== Request & Response types + +You can import the full TypeScript requests & responses defintions as it follows: + +[source,ts] +---- +import { estypes } from '@elastic/elasticsearch' +---- \ No newline at end of file