Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8de6f137de | |||
| 87c80b0a48 | |||
| 15a9479a81 | |||
| 11951fe8fc |
2
.github/workflows/nodejs.yml
vendored
2
.github/workflows/nodejs.yml
vendored
@ -63,7 +63,7 @@ jobs:
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
npm run test:unit -- --node-arg=--harmony-async-iteration
|
||||
npm run test:node8
|
||||
|
||||
helpers-integration-test:
|
||||
name: Helpers integration test
|
||||
|
||||
@ -1,6 +1,19 @@
|
||||
[[changelog-client]]
|
||||
== Changelog
|
||||
|
||||
=== 7.7.1
|
||||
|
||||
==== Fixes
|
||||
|
||||
===== Disable client Helpers in Node.js < 10 - https://github.com/elastic/elasticsearch-js/pull/1194[#1194]
|
||||
|
||||
The client helpers can't be used in Node.js < 10 because it needs a custom flag to be able to use them.
|
||||
Given that not every provider allows the user to specify cuatom Node.js flags, the Helpers has been disabled completely in Node.js < 10.
|
||||
|
||||
===== Force lowercase in all headers - https://github.com/elastic/elasticsearch-js/pull/1187[#1187]
|
||||
|
||||
Now all the user-provided headers names will be lowercased by default, so there will be no conflicts in case of the same header with different casing.
|
||||
|
||||
=== 7.7.0
|
||||
|
||||
==== Features
|
||||
|
||||
@ -4,8 +4,7 @@
|
||||
The client comes with an handy collection of helpers to give you a more comfortable experience with some APIs.
|
||||
|
||||
CAUTION: The client helpers are experimental, and the API may change in the next minor releases.
|
||||
If you are using the client with Node.js v8 you should run your code with the `--harmony-async-iteration` argument. +
|
||||
eg: `node --harmony-async-iteration index.js`
|
||||
The helpers will not work in any Node.js version lower than 10.
|
||||
|
||||
=== Bulk Helper
|
||||
Running Bulk requests can be complex due to the shape of the API, this helper aims to provide a nicer developer experience around the Bulk API.
|
||||
|
||||
9
index.js
9
index.js
@ -4,13 +4,16 @@
|
||||
|
||||
'use strict'
|
||||
|
||||
const nodeMajor = Number(process.versions.node.split('.')[0])
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
const { URL } = require('url')
|
||||
const debug = require('debug')('elasticsearch')
|
||||
const Transport = require('./lib/Transport')
|
||||
const Connection = require('./lib/Connection')
|
||||
const { ConnectionPool, CloudConnectionPool } = require('./lib/pool')
|
||||
const Helpers = require('./lib/Helpers')
|
||||
// Helpers works only in Node.js >= 10
|
||||
const Helpers = nodeMajor < 10 ? null : require('./lib/Helpers')
|
||||
const Serializer = require('./lib/Serializer')
|
||||
const errors = require('./lib/errors')
|
||||
const { ConfigurationError } = errors
|
||||
@ -127,7 +130,9 @@ class Client extends EventEmitter {
|
||||
opaqueIdPrefix: options.opaqueIdPrefix
|
||||
})
|
||||
|
||||
this.helpers = new Helpers({ client: this, maxRetries: options.maxRetries })
|
||||
if (Helpers !== null) {
|
||||
this.helpers = new Helpers({ client: this, maxRetries: options.maxRetries })
|
||||
}
|
||||
|
||||
const apis = buildApi({
|
||||
makeRequest: this.transport.request.bind(this.transport),
|
||||
|
||||
@ -34,9 +34,9 @@ class Transport {
|
||||
this.suggestCompression = opts.suggestCompression === true
|
||||
this.compression = opts.compression || false
|
||||
this.headers = Object.assign({},
|
||||
{ 'User-Agent': userAgent },
|
||||
opts.suggestCompression === true ? { 'Accept-Encoding': 'gzip,deflate' } : null,
|
||||
opts.headers
|
||||
{ 'user-agent': userAgent },
|
||||
opts.suggestCompression === true ? { 'accept-encoding': 'gzip,deflate' } : null,
|
||||
lowerCaseHeaders(opts.headers)
|
||||
)
|
||||
this.sniffInterval = opts.sniffInterval
|
||||
this.sniffOnConnectionFault = opts.sniffOnConnectionFault
|
||||
@ -243,10 +243,10 @@ class Transport {
|
||||
})
|
||||
}
|
||||
|
||||
const headers = Object.assign({}, this.headers, options.headers)
|
||||
const headers = Object.assign({}, this.headers, lowerCaseHeaders(options.headers))
|
||||
|
||||
if (options.opaqueId !== undefined) {
|
||||
headers['X-Opaque-Id'] = this.opaqueIdPrefix !== null
|
||||
headers['x-opaque-id'] = this.opaqueIdPrefix !== null
|
||||
? this.opaqueIdPrefix + options.opaqueId
|
||||
: options.opaqueId
|
||||
}
|
||||
@ -262,7 +262,7 @@ class Transport {
|
||||
}
|
||||
|
||||
if (params.body !== '') {
|
||||
headers['Content-Type'] = headers['Content-Type'] || 'application/json'
|
||||
headers['content-type'] = headers['content-type'] || 'application/json'
|
||||
}
|
||||
|
||||
// handle ndjson body
|
||||
@ -277,7 +277,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'] || 'application/x-ndjson'
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,7 +301,7 @@ class Transport {
|
||||
if (params.body !== '' && params.body != null) {
|
||||
if (isStream(params.body) === true) {
|
||||
if (compression === 'gzip') {
|
||||
params.headers['Content-Encoding'] = compression
|
||||
params.headers['content-encoding'] = compression
|
||||
params.body = params.body.pipe(createGzip())
|
||||
}
|
||||
makeRequest()
|
||||
@ -311,13 +311,13 @@ class Transport {
|
||||
if (err) {
|
||||
return callback(err, result)
|
||||
}
|
||||
params.headers['Content-Encoding'] = compression
|
||||
params.headers['Content-Length'] = '' + Buffer.byteLength(buffer)
|
||||
params.headers['content-encoding'] = compression
|
||||
params.headers['content-length'] = '' + Buffer.byteLength(buffer)
|
||||
params.body = buffer
|
||||
makeRequest()
|
||||
})
|
||||
} else {
|
||||
params.headers['Content-Length'] = '' + Buffer.byteLength(params.body)
|
||||
params.headers['content-length'] = '' + Buffer.byteLength(params.body)
|
||||
makeRequest()
|
||||
}
|
||||
} else {
|
||||
@ -453,5 +453,21 @@ function generateRequestId () {
|
||||
return (nextReqId = (nextReqId + 1) & maxInt)
|
||||
}
|
||||
}
|
||||
|
||||
function lowerCaseHeaders (oldHeaders) {
|
||||
if (oldHeaders == null) return oldHeaders
|
||||
const newHeaders = {}
|
||||
for (const header in oldHeaders) {
|
||||
newHeaders[header.toLowerCase()] = oldHeaders[header]
|
||||
}
|
||||
return newHeaders
|
||||
}
|
||||
|
||||
module.exports = Transport
|
||||
module.exports.internals = { defaultNodeFilter, roundRobinSelector, randomSelector, generateRequestId }
|
||||
module.exports.internals = {
|
||||
defaultNodeFilter,
|
||||
roundRobinSelector,
|
||||
randomSelector,
|
||||
generateRequestId,
|
||||
lowerCaseHeaders
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"homepage": "http://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/index.html",
|
||||
"version": "7.7.0",
|
||||
"version": "7.7.1",
|
||||
"keywords": [
|
||||
"elasticsearch",
|
||||
"elastic",
|
||||
@ -17,6 +17,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"test": "npm run lint && npm run test:unit && npm run test:behavior && npm run test:types",
|
||||
"test:node8": "npm run lint && tap test/unit/*.test.js -t 300 --no-coverage && npm run test:behavior && npm run test:types",
|
||||
"test:unit": "tap test/unit/*.test.js test/unit/**/*.test.js -t 300 --no-coverage",
|
||||
"test:behavior": "tap test/behavior/*.test.js -t 300 --no-coverage",
|
||||
"test:integration": "node test/integration/index.js",
|
||||
|
||||
@ -1029,3 +1029,41 @@ test('Opaque Id support', t => {
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Correctly handles the same header cased differently', t => {
|
||||
t.plan(4)
|
||||
|
||||
function handler (req, res) {
|
||||
t.strictEqual(req.headers['authorization'], 'Basic foobar')
|
||||
t.strictEqual(req.headers['foo'], 'baz')
|
||||
res.setHeader('Content-Type', 'application/json;utf=8')
|
||||
res.end(JSON.stringify({ hello: 'world' }))
|
||||
}
|
||||
|
||||
buildServer(handler, ({ port }, server) => {
|
||||
const client = new Client({
|
||||
node: `http://localhost:${port}`,
|
||||
auth: {
|
||||
username: 'hello',
|
||||
password: 'world'
|
||||
},
|
||||
headers: {
|
||||
Authorization: 'Basic foobar',
|
||||
Foo: 'bar'
|
||||
}
|
||||
})
|
||||
|
||||
client.search({
|
||||
index: 'test',
|
||||
q: 'foo:bar'
|
||||
}, {
|
||||
headers: {
|
||||
foo: 'baz'
|
||||
}
|
||||
}, (err, { body }) => {
|
||||
t.error(err)
|
||||
t.deepEqual(body, { hello: 'world' })
|
||||
server.stop()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -25,7 +25,7 @@ test('bulk index', t => {
|
||||
const MockConnection = connection.buildMockConnection({
|
||||
onRequest (params) {
|
||||
t.strictEqual(params.path, '/_bulk')
|
||||
t.match(params.headers, { 'Content-Type': 'application/x-ndjson' })
|
||||
t.match(params.headers, { 'content-type': 'application/x-ndjson' })
|
||||
const [action, payload] = params.body.split('\n')
|
||||
t.deepEqual(JSON.parse(action), { index: { _index: 'test' } })
|
||||
t.deepEqual(JSON.parse(payload), dataset[count++])
|
||||
@ -67,7 +67,7 @@ test('bulk index', t => {
|
||||
const MockConnection = connection.buildMockConnection({
|
||||
onRequest (params) {
|
||||
t.strictEqual(params.path, '/_bulk')
|
||||
t.match(params.headers, { 'Content-Type': 'application/x-ndjson' })
|
||||
t.match(params.headers, { 'content-type': 'application/x-ndjson' })
|
||||
const [action, payload] = params.body.split('\n')
|
||||
t.deepEqual(JSON.parse(action), { index: { _index: 'test' } })
|
||||
t.deepEqual(JSON.parse(payload), dataset[count++])
|
||||
@ -108,7 +108,7 @@ test('bulk index', t => {
|
||||
const MockConnection = connection.buildMockConnection({
|
||||
onRequest (params) {
|
||||
t.strictEqual(params.path, '/_bulk')
|
||||
t.match(params.headers, { 'Content-Type': 'application/x-ndjson' })
|
||||
t.match(params.headers, { 'content-type': 'application/x-ndjson' })
|
||||
t.strictEqual(params.body.split('\n').filter(Boolean).length, 6)
|
||||
return { body: { errors: false, items: new Array(3).fill({}) } }
|
||||
}
|
||||
@ -152,7 +152,7 @@ test('bulk index', t => {
|
||||
return { body: { acknowledged: true } }
|
||||
} else {
|
||||
t.strictEqual(params.path, '/_bulk')
|
||||
t.match(params.headers, { 'Content-Type': 'application/x-ndjson' })
|
||||
t.match(params.headers, { 'content-type': 'application/x-ndjson' })
|
||||
const [action, payload] = params.body.split('\n')
|
||||
t.deepEqual(JSON.parse(action), { index: { _index: 'test' } })
|
||||
t.deepEqual(JSON.parse(payload), dataset[count++])
|
||||
@ -193,7 +193,7 @@ test('bulk index', t => {
|
||||
const MockConnection = connection.buildMockConnection({
|
||||
onRequest (params) {
|
||||
t.strictEqual(params.path, '/_bulk')
|
||||
t.match(params.headers, { 'Content-Type': 'application/x-ndjson' })
|
||||
t.match(params.headers, { 'content-type': 'application/x-ndjson' })
|
||||
const [action, payload] = params.body.split('\n')
|
||||
t.deepEqual(JSON.parse(action), { index: { _index: 'test', _id: count } })
|
||||
t.deepEqual(JSON.parse(payload), dataset[count++])
|
||||
@ -607,7 +607,7 @@ test('bulk index', t => {
|
||||
const MockConnection = connection.buildMockConnection({
|
||||
onRequest (params) {
|
||||
t.strictEqual(params.path, '/_bulk')
|
||||
t.match(params.headers, { 'Content-Type': 'application/x-ndjson' })
|
||||
t.match(params.headers, { 'content-type': 'application/x-ndjson' })
|
||||
const [action, payload] = params.body.split('\n')
|
||||
t.deepEqual(JSON.parse(action), { index: { _index: 'test', _id: count } })
|
||||
t.deepEqual(JSON.parse(payload), dataset[count++])
|
||||
@ -659,7 +659,7 @@ test('bulk index', t => {
|
||||
const MockConnection = connection.buildMockConnection({
|
||||
onRequest (params) {
|
||||
t.strictEqual(params.path, '/_bulk')
|
||||
t.match(params.headers, { 'Content-Type': 'application/x-ndjson' })
|
||||
t.match(params.headers, { 'content-type': 'application/x-ndjson' })
|
||||
const [action, payload] = params.body.split('\n')
|
||||
t.deepEqual(JSON.parse(action), { index: { _index: 'test' } })
|
||||
t.deepEqual(JSON.parse(payload), dataset[count++])
|
||||
@ -715,7 +715,7 @@ test('bulk create', t => {
|
||||
const MockConnection = connection.buildMockConnection({
|
||||
onRequest (params) {
|
||||
t.strictEqual(params.path, '/_bulk')
|
||||
t.match(params.headers, { 'Content-Type': 'application/x-ndjson' })
|
||||
t.match(params.headers, { 'content-type': 'application/x-ndjson' })
|
||||
const [action, payload] = params.body.split('\n')
|
||||
t.deepEqual(JSON.parse(action), { create: { _index: 'test', _id: count } })
|
||||
t.deepEqual(JSON.parse(payload), dataset[count++])
|
||||
@ -764,7 +764,7 @@ test('bulk update', t => {
|
||||
const MockConnection = connection.buildMockConnection({
|
||||
onRequest (params) {
|
||||
t.strictEqual(params.path, '/_bulk')
|
||||
t.match(params.headers, { 'Content-Type': 'application/x-ndjson' })
|
||||
t.match(params.headers, { 'content-type': 'application/x-ndjson' })
|
||||
const [action, payload] = params.body.split('\n')
|
||||
t.deepEqual(JSON.parse(action), { update: { _index: 'test', _id: count } })
|
||||
t.deepEqual(JSON.parse(payload), { doc: dataset[count++], doc_as_upsert: true })
|
||||
@ -815,7 +815,7 @@ test('bulk delete', t => {
|
||||
const MockConnection = connection.buildMockConnection({
|
||||
onRequest (params) {
|
||||
t.strictEqual(params.path, '/_bulk')
|
||||
t.match(params.headers, { 'Content-Type': 'application/x-ndjson' })
|
||||
t.match(params.headers, { 'content-type': 'application/x-ndjson' })
|
||||
t.deepEqual(JSON.parse(params.body), { delete: { _index: 'test', _id: count++ } })
|
||||
return { body: { errors: false, items: [{}] } }
|
||||
}
|
||||
|
||||
@ -2416,3 +2416,32 @@ test('Secure json parsing', t => {
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Lowercase headers utilty', t => {
|
||||
t.plan(4)
|
||||
const { lowerCaseHeaders } = Transport.internals
|
||||
|
||||
t.deepEqual(lowerCaseHeaders({
|
||||
Foo: 'bar',
|
||||
Faz: 'baz',
|
||||
'X-Hello': 'world'
|
||||
}), {
|
||||
foo: 'bar',
|
||||
faz: 'baz',
|
||||
'x-hello': 'world'
|
||||
})
|
||||
|
||||
t.deepEqual(lowerCaseHeaders({
|
||||
Foo: 'bar',
|
||||
faz: 'baz',
|
||||
'X-hello': 'world'
|
||||
}), {
|
||||
foo: 'bar',
|
||||
faz: 'baz',
|
||||
'x-hello': 'world'
|
||||
})
|
||||
|
||||
t.strictEqual(lowerCaseHeaders(null), null)
|
||||
|
||||
t.strictEqual(lowerCaseHeaders(undefined), undefined)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user