Add api compatibility header support (#1478) (#1491)

Co-authored-by: Tomas Della Vedova <delvedor@users.noreply.github.com>
This commit is contained in:
github-actions[bot]
2021-07-13 09:48:30 +02:00
committed by GitHub
parent ea2c8d2d4d
commit 28d8ff799e
4 changed files with 75 additions and 4 deletions

View File

@ -84,3 +84,17 @@ const client = new Client({
Serializer: MySerializer
})
----
[discrete]
==== Migrate to v8
The Node.js client can be configured to emit an HTTP header
``Accept: application/vnd.elasticsearch+json; compatible-with=7``
which signals to Elasticsearch that the client is requesting
``7.x`` version of request and response bodies. This allows for
upgrading from 7.x to 8.x version of Elasticsearch without upgrading
everything at once. Elasticsearch should be upgraded first after
the compatibility header is configured and clients should be upgraded
second.
To enable to setting, configure the environment variable
``ELASTIC_CLIENT_APIVERSIONING`` to ``true``.

View File

@ -116,6 +116,10 @@ class Client extends ESAPI {
disablePrototypePoisoningProtection: false
}, opts)
if (process.env.ELASTIC_CLIENT_APIVERSIONING === 'true') {
options.headers = Object.assign({ accept: 'application/vnd.elasticsearch+json; compatible-with=7' }, options.headers)
}
this[kInitialOptions] = options
this[kExtensions] = []
this.name = options.name

View File

@ -38,6 +38,7 @@ const clientVersion = require('../package.json').version
const userAgent = `elasticsearch-js/${clientVersion} (${os.platform()} ${os.release()}-${os.arch()}; Node.js ${process.version})`
const MAX_BUFFER_LENGTH = buffer.constants.MAX_LENGTH
const MAX_STRING_LENGTH = buffer.constants.MAX_STRING_LENGTH
const kApiVersioning = Symbol('api versioning')
class Transport {
constructor (opts) {
@ -64,6 +65,7 @@ class Transport {
this.generateRequestId = opts.generateRequestId || generateRequestId()
this.name = opts.name
this.opaqueIdPrefix = opts.opaqueIdPrefix
this[kApiVersioning] = process.env.ELASTIC_CLIENT_APIVERSIONING === 'true'
this.nodeFilter = opts.nodeFilter || defaultNodeFilter
if (typeof opts.nodeSelector === 'function') {
@ -295,7 +297,8 @@ class Transport {
// - the request is not a HEAD request
// - the payload is not an empty string
if (result.headers['content-type'] !== undefined &&
result.headers['content-type'].indexOf('application/json') > -1 &&
(result.headers['content-type'].indexOf('application/json') > -1 ||
result.headers['content-type'].indexOf('application/vnd.elasticsearch+json') > -1) &&
isHead === false &&
payload !== ''
) {
@ -369,7 +372,7 @@ class Transport {
}
if (params.body !== '') {
headers['content-type'] = headers['content-type'] || 'application/json'
headers['content-type'] = headers['content-type'] || (this[kApiVersioning] ? 'application/vnd.elasticsearch+json; compatible-with=7' : 'application/json')
}
// handle ndjson body
@ -386,7 +389,7 @@ class Transport {
params.body = params.bulkBody
}
if (params.body !== '') {
headers['content-type'] = headers['content-type'] || 'application/x-ndjson'
headers['content-type'] = headers['content-type'] || (this[kApiVersioning] ? 'application/vnd.elasticsearch+x-ndjson; compatible-with=7' : 'application/x-ndjson')
}
}

View File

@ -1422,6 +1422,56 @@ test('Disable prototype poisoning protection', t => {
})
})
test('API compatibility header (json)', t => {
t.plan(4)
function handler (req, res) {
t.equal(req.headers.accept, 'application/vnd.elasticsearch+json; compatible-with=7')
t.equal(req.headers['content-type'], 'application/vnd.elasticsearch+json; compatible-with=7')
res.setHeader('Content-Type', 'application/vnd.elasticsearch+json; compatible-with=7')
res.end(JSON.stringify({ hello: 'world' }))
}
buildServer(handler, ({ port }, server) => {
process.env.ELASTIC_CLIENT_APIVERSIONING = 'true'
const client = new Client({
node: `http://localhost:${port}`
})
client.index({ index: 'foo', body: {} }, (err, { body }) => {
t.error(err)
t.same(body, { hello: 'world' })
server.stop()
delete process.env.ELASTIC_CLIENT_APIVERSIONING
})
})
})
test('API compatibility header (x-ndjson)', t => {
t.plan(4)
function handler (req, res) {
t.equal(req.headers.accept, 'application/vnd.elasticsearch+json; compatible-with=7')
t.equal(req.headers['content-type'], 'application/vnd.elasticsearch+x-ndjson; compatible-with=7')
res.setHeader('Content-Type', 'application/vnd.elasticsearch+json; compatible-with=7')
res.end(JSON.stringify({ hello: 'world' }))
}
buildServer(handler, ({ port }, server) => {
process.env.ELASTIC_CLIENT_APIVERSIONING = 'true'
const client = new Client({
node: `http://localhost:${port}`
})
client.bulk({ index: 'foo', body: [{}, {}] }, (err, { body }) => {
t.error(err)
t.same(body, { hello: 'world' })
server.stop()
delete process.env.ELASTIC_CLIENT_APIVERSIONING
})
})
})
test('Bearer auth', t => {
t.plan(3)