Reusable helper functions to help you build request parameters and parse response data
ES Kit works on the basis that Document and Search API calls follow a similar lifecycle so the helpers abstract each part:
1. Build parameters:
2. Make the request:
- build a bulk query
- merge any defaults
3. Parse the response:
4. Handle errors:
You can use the helpers directly or indirectly via the Api class (which uses them internally).
You should know that the code for each of the helpers is simple and straightforward but also make decisions on how to convert arguments into request parameters or response data. However, the helpers are designed to be atomic which means you can replace them if you need to, which will update the functionality of both the individual helper and the Api method which uses them.
If you're not using the Api and you don't want to replace them, simply use your own code where you need to.
You can import the helpers in several ways:
// import as a single object (which will code-complete)
import { Helpers } from `@davestewart/es-kit`
// import and rename as something easier to type
import { Helpers as $ } from `@davestewart/es-kit`
// import individually
import { $painless, $query } from `@davestewart/es-kit`
Once imported, use the individual helpers to build query options or parse responses:
// build options
const options = {
index: 'contacts',
sort: $.sort('name')
query: $.query(res.params),
}
// call the api
const res = await client.search(options)
// parse results
return $.paginate(res, options)
Each of the helpers is typed, so expect proper auto-completion and warnings as you use them.
Note that the easiest way to see what the code does it to look at it.
The request helpers help you build configuration to pass to the Elasticsearch client's methods.
The query helper is designed to convert a hash of values (such as request.params
) into a sensible compound Elastic query.
function $query (
fields: Record<string, any>,
options: { type: 'and' | 'or' = 'and', exact: boolean = false } = {}
): BooleanQuery | Query
It handles:
- and / or (must / should)
- phrase / exact (match / term)
- multimatch (pass
*
as field name) - wildcards (pass
*
as field value)
The request helper is built on top of the Queru helper to directly convert a URLRequest's params
and query
values into a sensible compound Elastic query.
function $request (
request: URLRequest
): BooleanQuery | Query
The script() helper builds a ScriptOption
configuration:
function $script (
source: string | Function,
params?: object
): ScriptOption
Pass a function
or string
and optional params
object:
const script = $.script(function (ctx, params) {
if (ctx.value > 5) {
ctx.value *= params.multiplier
}
}, { multiplier: 10 })
{
lang: 'painless',
source: 'if (ctx.value > 5) { ctx.value *= params.multiplier; }',
params: {
multiplier: 10
}
}
Note that Painless-objects are expected to be Java, so whilst the code will compile, and may be testable, it may not be runnable in your JS environment.
The painless helper converts a JavaScript function into Painless string:
function $painless (source: Function | string): string
It works by:
- converting the function to a string
- punctuating with semicolons
- replacing common keywords
- optimising those keywords
- removing strict equality
- concatenating into a single line
The sort() helper builds a SortOption
array:
function $sort (
field: string | string[] | Record<string, string | boolean | number>,
keyword?: boolean
): Record<string, SortOption>
Pass a string, array of strings, or object, with optionalkeyword
flag:
const sort = $.sort({ name: true, age: false }, true)
[{ 'name.keyword': 'asc' }, { 'age.keyword': 'desc' }
The bulk helpers are designed to build queries for the Bulk APIs without having to resort to a flatMap
.
function $bulk.search (
index: string,
queries: Query[],
options: SearchOptions = {}
): object[]
function $bulk.index (
index: string,
queries: Query[],
id?: string
): object[]
Rather than flattening an array which will (generally have the same index
) you pass the index
and the queries
separately and the helper will interleve them for you:
const values = ['foo', 'bar', 'baz']
const queries = values.map(value => _.match('name', text))
const bulk = $bulk.search('options', queries)
[
{ index: { _index: 'options' } },
{ query: { match: { value: 'foo' } } },
{ index: { _index: 'options' } },
{ query: { match: { value: 'bar' } } },
{ index: { _index: 'options' } },
{ query: { match: { value: 'baz' } } },
]
The defaults helper is designed to create a top level options object using defaults you can override.
function $defaults (options: SearchOptions): SearchOptions
The response helpers help you simplify the verbose and somewhat inconsistent response formats from the Search and Document APIs.
The extract helper...
The results helper converts results from the Search or Document API to a consistent format.
function $results (
res: any,
req: any,
type?: string
): object | object[]
The paginate helper paginates results in a consistent and intuitive format.
function $paginate (
res: any,
options: SearchOptions
): { meta: object, hits: object[] }
The doc helper extracts individual hits, results or responses to a consistent format.
function $doc (
hit: any,
source: any = {}
): object
The fields helper remaps document fields to alternate structures as required.
function $fields (
doc: Record<string, any>,
fields: Record<string, string> | Function
): object
The error helper converts the various Elastic error responses to a simple, consistent format.
function $error (error: any): object
The log helper outputs both request and response data as the Api makes its calls.
function $log (
label: string,
data: any = null
): void
The pupose of ES Kit's helpers is to abstract the common API lifecycle functionality into reusable functions.
They aim to provide sensible defaults, but if they don't work for you, they can easily be replaced by your own functions, enabling you to change how request and response data is processed. This allows you to continue using the ES Kit Api class without having to break out to vanilla JavaScript each time you want to make an API call.
To replace a helper, simply import the main Helpers
object, and assign the replacement function:
import { Helpers } from '@davestewart/es-kit'
Helpers.doc = function (hit, source) {
return hit // return hits as-is
}
Note that extending
Helpers
will not overwrite the individual exported$
style helpers, as decribed above.