287 lines
8.3 KiB
Plaintext
287 lines
8.3 KiB
Plaintext
== Breaking changes coming from the old client
|
||
|
||
If you were already using the previous version of this client --i.e. the one you used to install with `npm install elasticsearch`-- you will encounter some breaking changes.
|
||
|
||
=== 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.
|
||
|
||
=== Breaking changes
|
||
|
||
* Minimum supported version of Node.js is `v6`.
|
||
|
||
* 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 Elasticsearch `v6`, you will be 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.
|
||
|
||
* No more 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 just 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`. Each error class has been renamed, and now each is suffixed with `Error` at the end.
|
||
|
||
* Errors that have been removed: `RequestTypeError`, `Generic`, and all the status code specific errors (such as `BadRequest` or `NotFound`).
|
||
|
||
* Errors that have been added: `ConfigurationError` (in case of bad configurations) and `ResponseError`, which contains all the data you may need to handle the specific error, such as `statusCode`, `headers`, `body`, and `message`.
|
||
|
||
|
||
* Errors that has been renamed:
|
||
|
||
** `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 via the `node` parameter.
|
||
|
||
* 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 should 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 will no longer accept the `query` key, but the `querystring` key instead (which can be a string or an object), furthermore, you need to send a bulk-like request, instead of the `body` key, you should use the `bulkBody` key. Also 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)
|
||
})
|
||
----
|
||
|
||
=== Talk is cheap. Show me the code.
|
||
|
||
Following you will find a snippet of code with the old client, 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)
|
||
}
|
||
})
|
||
----
|