[DOCS] Adds Integrations section to Node.JS docs (#1407)

Co-authored-by: Tomas Della Vedova <delvedor@users.noreply.github.com>
This commit is contained in:
István Zoltán Szabó
2021-03-10 17:13:15 +01:00
committed by GitHub
parent 22ece32c5c
commit 36eaed6466
8 changed files with 139 additions and 115 deletions

View File

@ -4,45 +4,11 @@
If you need to customize the client behavior heavily, you are in the right If you need to customize the client behavior heavily, you are in the right
place! The client enables you to customize the following internals: place! The client enables you to customize the following internals:
* `Transport` class
* `ConnectionPool` class * `ConnectionPool` class
* `Connection` class * `Connection` class
* `Serializer` class * `Serializer` class
NOTE: For information about the `Transport` class, refer to <<transport>>.
[discrete]
==== `Transport`
This class is responsible for performing the request to {es} and handling
errors, it also handles the sniffing.
[source,js]
----
const { Client, Transport } = require('@elastic/elasticsearch')
class MyTransport extends Transport {
request (params, options, callback) {
// your code
}
}
const client = new Client({
Transport: MyTransport
})
----
Sometimes you need to inject a small snippet of your code and then continue to
use the usual client code. In such cases, call `super.method`:
[source,js]
----
class MyTransport extends Transport {
request (params, options, callback) {
// your code
return super.request(params, options, callback)
}
}
----
[discrete] [discrete]

View File

@ -9,3 +9,4 @@ section, you can see the possible options that you can use to configure it.
* <<advanced-config>> * <<advanced-config>>
* <<child>> * <<child>>
* <<extend>> * <<extend>>
* <<client-testing>>

View File

@ -11,10 +11,12 @@ include::basic-config.asciidoc[]
include::advanced-config.asciidoc[] include::advanced-config.asciidoc[]
include::child.asciidoc[] include::child.asciidoc[]
include::extend.asciidoc[] include::extend.asciidoc[]
include::testing.asciidoc[]
include::integrations.asciidoc[]
include::observability.asciidoc[]
include::transport.asciidoc[]
include::typescript.asciidoc[]
include::reference.asciidoc[] include::reference.asciidoc[]
include::breaking-changes.asciidoc[] include::breaking-changes.asciidoc[]
include::observability.asciidoc[]
include::helpers.asciidoc[] include::helpers.asciidoc[]
include::typescript.asciidoc[]
include::testing.asciidoc[]
include::examples/index.asciidoc[] include::examples/index.asciidoc[]

View File

@ -0,0 +1,8 @@
[[integrations]]
== Integrations
The Client offers the following integration options for you:
* <<observability>>
* <<transport>>
* <<typescript>>

View File

@ -1,19 +1,19 @@
[[observability]] [[observability]]
== Observability === Observability
The client does not provide a default logger, but instead it offers an event 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 interfaces to hook into internal events, such as `request` and
`response`. `response`.
Correlating those events can be quite hard, especially if your applications have Correlating those events can be hard, especially if your applications have a
a large codebase with many events happening at the same time. large codebase with many events happening at the same time.
To help you with this, the client offers you a correlation id system and other To help you with this, the client offers you a correlation id system and other
features. Let's see them in action. features. Let's see them in action.
[discrete] [discrete]
=== Events ==== Events
The client is an event emitter, this means that you can listen for its event and The client is an event emitter, this means that you can listen for its event and
add additional logic to your code, without need to change the client internals add additional logic to your code, without need to change the client internals
@ -105,7 +105,8 @@ client.on('resurrect', (err, result) => {
|=== |===
The values of `result` in `serialization`, `request`, `deserialization`, `response` and `sniff` will be: The values of `result` in `serialization`, `request`, `deserialization`,
`response` and `sniff` are:
[source,ts] [source,ts]
---- ----
@ -132,7 +133,7 @@ meta: {
---- ----
While the `result` value in `resurrect` will be: While the `result` value in `resurrect` is:
[source,ts] [source,ts]
---- ----
@ -146,10 +147,13 @@ request: {
---- ----
[discrete] [discrete]
==== Events order ===== Events order
The event order is described in the following graph, in some edge cases, the order is not guaranteed. The event order is described in the following graph, in some edge cases, the
You can find in https://github.com/elastic/elasticsearch-js/blob/master/test/acceptance/events-order.test.js[`test/acceptance/events-order.test.js`] how the order changes based on the situation. order is not guaranteed.
You can find in
https://github.com/elastic/elasticsearch-js/blob/master/test/acceptance/events-order.test.js[`test/acceptance/events-order.test.js`]
how the order changes based on the situation.
[source] [source]
---- ----
@ -170,11 +174,11 @@ serialization
[discrete] [discrete]
=== Correlation id ==== Correlation id
Correlating events can be quite hard, especially if there are many events at the Correlating events can be hard, especially if there are many events at the same
same time. The client offers you an automatic (and configurable) system to help time. The client offers you an automatic (and configurable) system to help you
you handle this problem. handle this problem.
[source,js] [source,js]
---- ----
@ -204,8 +208,8 @@ client.search({
---- ----
By default the id is an incremental integer, but you can easily configure that By default the id is an incremental integer, but you can configure it with the
with the `generateRequestId` option: `generateRequestId` option:
[source,js] [source,js]
---- ----
@ -238,7 +242,7 @@ client.search({
[discrete] [discrete]
=== Context object ==== Context object
Sometimes, you might need to make some custom data available in your events, you Sometimes, you might need to make some custom data available in your events, you
can do that via the `context` option of a request: can do that via the `context` option of a request:
@ -275,8 +279,8 @@ client.search({
---- ----
The context object can also be configured as a global option in the client The context object can also be configured as a global option in the client
configuration. If you provide both, the two context object will be shallow merged, configuration. If you provide both, the two context objects will be shallow
and the API level object will take precedece. merged, and the API level object will take precedence.
[source,js] [source,js]
---- ----
@ -314,12 +318,12 @@ client.search({
[discrete] [discrete]
=== Client name ==== Client name
If you are using multiple instances of the client or if you are using multiple If you are using multiple instances of the client or if you are using multiple
child clients _(which is the recommended way to have multiple instances of the child clients _(which is the recommended way to have multiple instances of the
client)_, you might need to recognize which client you are using. The `name` client)_, you might need to recognize which client you are using. The `name`
options will help you in this regard. options help you in this regard.
[source,js] [source,js]
---- ----
@ -368,13 +372,13 @@ child.search({
[discrete] [discrete]
=== X-Opaque-Id support ==== X-Opaque-Id support
To improve the overall observability, the client offers an easy way to configure To improve observability, the client offers an easy way to configure the
the `X-Opaque-Id` header. If you set the `X-Opaque-Id` in a specific request, `X-Opaque-Id` header. If you set the `X-Opaque-Id` in a specific request, this
this will allow you to discover this identifier in the allows you to discover this identifier in the
https://www.elastic.co/guide/en/elasticsearch/reference/master/logging.html#deprecation-logging[deprecation logs], https://www.elastic.co/guide/en/elasticsearch/reference/master/logging.html#deprecation-logging[deprecation logs],
help you with https://www.elastic.co/guide/en/elasticsearch/reference/master/index-modules-slowlog.html#_identifying_search_slow_log_origin[identifying search slow log origin] helps you with https://www.elastic.co/guide/en/elasticsearch/reference/master/index-modules-slowlog.html#_identifying_search_slow_log_origin[identifying search slow log origin]
as well as https://www.elastic.co/guide/en/elasticsearch/reference/master/tasks.html#_identifying_running_tasks[identifying running tasks]. as well as https://www.elastic.co/guide/en/elasticsearch/reference/master/tasks.html#_identifying_running_tasks[identifying running tasks].
The `X-Opaque-Id` should be configured in each request, for doing that you can The `X-Opaque-Id` should be configured in each request, for doing that you can

View File

@ -1,56 +1,58 @@
[[client-testing]] [[client-testing]]
== Testing === Testing
Testing is one of the most important parts of developing an application. Testing is one of the most important parts of developing an application.
The client is very flexible when it comes to testing and is compatible with The client is very flexible when it comes to testing and is compatible with
most testing frameworks (such as https://www.npmjs.com/package/ava[`ava`], most testing frameworks (such as https://www.npmjs.com/package/ava[`ava`],
which is used in the examples below). which is used in the examples below).
If you are using this client, you are very likely working with Elasticsearch, If you are using this client, you are most likely working with {es}, and one of
and one of the first issues you will face is how to test your application. the first issues you face is how to test your application. A perfectly valid
A perfectly valid solution is to use the real Elasticsearch instance for solution is to use the real {es} instance for testing your application, but you
testing your application, but you would be doing an integration test, would be doing an integration test, while you want a unit test. There are many
while you want a unit test. ways to solve this problem, you could create the database with Docker, or use an
There are many ways to solve this problem, you could create the database in-memory compatible one, but if you are writing unit tests that can be easily
with docker, or use an in-memory compatible one, but if you are writing parallelized this becomes quite uncomfortable. A different way of improving your
unit tests that can be easily parallelized this will become quite uncomfortable. testing experience while doing unit tests is to use a mock.
A different way of improving your testing experience while doing unit tests
is to use a mock.
The client is designed to be easy to extend and adapt to your needs. The client is designed to be easy to extend and adapt to your needs. Thanks to
Thanks to its internal architecture it allows you to change some specific its internal architecture it allows you to change some specific components while
components while keeping the rest of it working as usual. keeping the rest of it working as usual. Each {es} official client is composed
Each Elasticsearch official client is composed of the following components: of the following components:
* `API layer`: every Elasticsearch API that you can call * `API layer`: every {es} API that you can call.
* `Transport`: a component that takes care of preparing a request before sending it and handling all the retry and sniffing strategies * `Transport`: a component that takes care of preparing a request before sending
* `ConnectionPool`: Elasticsearch is a cluster and might have multiple nodes, the * `ConnectionPool` takes care of them it and handling all the retry and sniffing strategies.
* `Serializer`: A class with all the serialization strategies, from the basic JSON to the new line delimited JSON. * `ConnectionPool`: {es} is a cluster and might have multiple nodes, the
`ConnectionPool` takes care of them.
* `Serializer`: A class with all the serialization strategies, from the basic
JSON to the new line delimited JSON.
* `Connection`: The actual HTTP library. * `Connection`: The actual HTTP library.
The best way to mock Elasticsearch with the official clients is to replace The best way to mock {es} with the official clients is to replace the
the `Connection` component since it has very few responsibilities and `Connection` component since it has very few responsibilities and it does not
it does not interact with other internal components other than getting interact with other internal components other than getting requests and
requests and returning responses. returning responses.
[discrete] [discrete]
=== `@elastic/elasticsearch-mock` ==== `@elastic/elasticsearch-mock`
Writing each time a mock for your test can be annoying and error-prone, Writing each time a mock for your test can be annoying and error-prone, so we
so we have built a simple yet powerful mocking library specifically designed have built a simple yet powerful mocking library specifically designed for this
for this client, and you can install it with the following command: client, and you can install it with the following command:
[source,sh] [source,sh]
---- ----
npm install @elastic/elasticsearch-mock --save-dev npm install @elastic/elasticsearch-mock --save-dev
---- ----
With this library you can easily create custom mocks for any request you can With this library you can create custom mocks for any request you can send to
send to Elasticsearch. It offers a simple and intuitive API and it mocks only {es}. It offers a simple and intuitive API and it mocks only the HTTP layer,
the HTTP layer, leaving the rest of the client working as usual. leaving the rest of the client working as usual.
Before showing all of its features, and what you can do with it, lets see an example: Before showing all of its features, and what you can do with it, lets see an
example:
[source,js] [source,js]
---- ----
@ -73,16 +75,16 @@ mock.add({
client.info(console.log) client.info(console.log)
---- ----
As you can see it works closely with the client itself, once you have created As you can see it works closely with the client itself, once you have created a
a new instance of the mock library you just need to call the mock.getConnection() new instance of the mock library you just need to call the mock.getConnection()
method and pass its result to the Connection option of the client. method and pass its result to the Connection option of the client. From now on,
From now on, every request will be handled by the mock library, and the HTTP every request is handled by the mock library, and the HTTP layer will never be
layer will never be touched. As a result, your test will be significantly faster touched. As a result, your test is significantly faster and you are able to
and you will be able to easily parallelize them! easily parallelize them!
The library allows you to write both “strict” and “loose” mocks, which means The library allows you to write both “strict” and “loose” mocks, which means
that you can write a mock that will handle a very specific request or be looser that you can write a mock that handles a very specific request or be looser and
and handle a group of request, lets see this in action: handle a group of request, lets see this in action:
[source,js] [source,js]
---- ----
@ -112,9 +114,9 @@ mock.add({
}) })
---- ----
In the example above every search request will get the first response, In the example above, every search request gets the first response, while every
while every search request that uses the query described in the second mock, search request that uses the query described in the second mock gets the second
will get the second response. response.
You can also specify dynamic paths: You can also specify dynamic paths:
@ -150,5 +152,6 @@ mock.add({
}) })
---- ----
We have seen how simple is mocking Elasticsearch and testing your application, We have seen how simple is mocking {es} and testing your application, you can
you can find many more features and examples in the https://github.com/elastic/elasticsearch-js-mock[module documentation]. find many more features and examples in the
https://github.com/elastic/elasticsearch-js-mock[module documentation].

34
docs/transport.asciidoc Normal file
View File

@ -0,0 +1,34 @@
[[transport]]
=== Transport
This class is responsible for performing the request to {es} and handling
errors, it also handles sniffing.
[source,js]
----
const { Client, Transport } = require('@elastic/elasticsearch')
class MyTransport extends Transport {
request (params, options, callback) {
// your code
}
}
const client = new Client({
Transport: MyTransport
})
----
Sometimes you need to inject a small snippet of your code and then continue to
use the usual client code. In such cases, call `super.method`:
[source,js]
----
class MyTransport extends Transport {
request (params, options, callback) {
// your code
return super.request(params, options, callback)
}
}
----

View File

@ -1,17 +1,23 @@
[[typescript]] [[typescript]]
== TypeScript support === TypeScript support
The client offers a first-class support for TypeScript, since it ships the type The client offers a first-class support for TypeScript, since it ships the type
definitions for every exposed API. definitions for every exposed API.
NOTE: If you are using TypeScript you will be required to use _snake_case_ style NOTE: If you are using TypeScript you need to use _snake_case_ style to define
to define the API parameters instead of _camelCase_. the API parameters instead of _camelCase_.
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. 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. 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: The body defaults to `RequestBody` and `RequestNDBody`, which are defined as
follows:
[source,ts] [source,ts]
---- ----
@ -39,7 +45,7 @@ You don't have to specify all the generics, but the order must be respected.
[discrete] [discrete]
=== A complete example ==== A complete example
[source,ts] [source,ts]
---- ----