A newer version is available. For the latest information, see the
current release documentation.
Breaking changes coming from the old client
editBreaking changes coming from the old client
editIf 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.
Don’t panic!
editEvery 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.
Breaking changes
edit-
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
, anderror
. -
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 Elasticsearch
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
, andheaders
for callbacks, and only thebody
for promises. The new returned value will be a unique object containing thebody
,statusCode
,headers
,warnings
, andmeta
, for both callback and promises.
// 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
orNotFound
). There is instead a singleResponseError
. Every error class has been renamed, and now each is suffixed withError
at the end. -
Removed errors:
RequestTypeError
,Generic
, and all the status code specific errors (such asBadRequest
orNotFound
). -
Added errors:
ConfigurationError
(in case of bad configurations) andResponseError
that contains all the data you may need to handle the specific error, such asstatusCode
,headers
,body
, andmessage
. -
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 tofalse
inside thessl
configuration:
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 theclient.extend
API.
// 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
andmaxRetries
are no longer part of the API object and you need to specify them in a second option object.
// 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 thequery
key. Use thequerystring
key instead (which can be a string or an object). You also need to send a bulk-like request instead of thebody
key, use thebulkBody
key. In this method, the client specific parameters should be passed as a second object.
// 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) })
Talk is cheap. Show me the code.
editYou can find a code snippet with the old client below followed by the same code logic but with the new client.
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.
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) } })