Options
All
  • Public
  • Public/Protected
  • All
Menu

HAIVE SearchClient

Haive SearchClient

NPM NPM Downloads Build Status

Project links

About

The SearchClient library makes it easy to hook up your search-UI to a Haive SearchManager instance (see the app-search features of Haive App Search here).

Note: in v2+ the package namespace is Haive (instead of IntelliSearch)

The package handles all the backend web-services so that you can focus on the user interface instead.

The SearchClient wraps and manages all the Haive SearchManager REST web-services:

  • Autocomplete - Lookups query-text and suggests words to help write the query.
  • Find - Searches the index based on the current query (query-text, filters, ...).
  • Categorize - Generates a category tree with counts based on the current query (query-text, filters, ...)

In addition, it also handles a OpenID authentication.

Use in NPM projects

For projects that consumes npm packages natively you add this package as you would add any other npm-package:

> npm install --save search-client

Since we have implemented the search-client in Typescript all the data-types and signatures are available for your IDE to use as intellisense. Please also use the documentation available in the generated API-documentation in the search-client doc-folder (typically ./node_modules/search-client/doc/index.html).

Use in browser (via script-tag)

For web-pages that needs to have a script-tag embedded you can fetch the file(s) needed via the jsDelivr cdn, like this:

<script src="//cdn.jsdelivr.net/npm/search-client@{version}/dist/Haive.min.js"></script>

- where {version} is to be replaced with the actual version you want.

CDN version aliases:

We strongly recommend that you use the full version id for production sites. For development sites we do recommend the same, but we also see that using a version alias might be handy in some cases.

  • latest You can use the jsdelivr version alias latest to always just get the latest version. Just be warned that your site is at high risk of breaking when new versions of the search-client are released. If the search-client library is updated and somehow is no longer compatible with your code, then your site will potentially break and stop working.

  • <Major> (i.e. 1) This means that it will get the latest version for the given major version. Note that the same warning as for latest applies, although this is less risky than just getting any latest version.

  • <Major.Minor> (i.e. 1.1) This means that it will get the latest version for the given major.minor version. Note that the same warning as for latest applies, although this is less risky than both of the above options.

Note: You can replace dist with es to get different builds of the library too. For browser script you should use dist as that version is in UMD format. A benefit to using the npm system is the inclusion of map-files. These are available for the es and lib versions only. Next to the browser-bundles in the project you can find accompanying .map files that browsers are able to utilize in order to give a better debugging experience.

License

LICENCE

Getting started

Basics

This section will cover only the basics. We highly recommend using the API-documentation for more details and insight.

The two central classes are SearchClient and Settings:

SearchClient

The central class is the SearchClient. To start using it you will need to create a new instance of it.

Note: If you are embedding the library via a script-tag then all the library features are in the Haive namespace.

The constructor takes one parameter (settings: ISettings), where at least the Settings.baseUrl must be set.

The settings interface has properties that help you customize the solution to your needs. The baseUrl is typically "http://<your-server>:9950" for the Haive SearchManager.

We recommend using the automatic mode, where you only need to interface with the SearchClient class and it's settings.

Settings

The Settings class has the following properties:

  • baseUrl: string - The base url for the endpoint (domain + port only).
  • basePath: string - The path (default usually is correct: "RestService/v4)"
  • authentication: AuthenticationSettings - Defines how authentication-calls are handled
  • autocomplete: AutocompleteSettings - Defines how autocomplete-calls are handled
  • categorize: CategorizeSettings - Defines how categorize-calls are handled
  • find: FindSettings - Defines how find-calls are handled
  • query: Query - Defines the default query-options.\

Please consult the documentation for specific details on each of them. Suffice to say that all the *Settings classes contains a boolean property called enabled, which by default is true.

Automatic mode

The automatic mode is by far the simplest and sexiest way for you as a developer to use the search-client. It makes it very easy for you to hook up your search-ui to the search-backend, without you having to add source code to detect when and how the various features are to be executed. Instead you can "stand on our shoulders" and leverage the knowledge that is already incorporated into the implemented automated triggers. You can set things up and it should "just work". We do however suggest that you invest time into understanding the various search-features and how the the triggers work. That will help you find the best way to implement the search-backend for your needs.

Set up triggers

The Autocomplete, Categorize, Find (and optionally also the authentication) services are all essential parts of the automatic mode. Because of this their respective settings objects also contain a property called trigger:

We suggest spending time on examining the triggers for the respective services above.

Set up callbacks

The automatic mode operations (autocomplete, categorize and find) also allow you to specify callbacks as a part of the configuration. The callbacks can be used in the manual mode too, but they were designed to be part of the automatic mode primarily.

  1. cbRequest This callback is called before the request is started. Typically you will use this to control loading/waiting indicators on the page. The signature includes some optional params (url: string, reqInit: RequestInit): bool.

    Note that if you add this callback, and explicitly return false, then the request will not be executed.

If you don't return or return false then the request runs as expected.

  1. cbSuccess This callback is called whenever a backend operation has completed and results have been received. The signature of the callback should be (data: <TDataType>) => void, where the <TDataType> is string[] for the autocomplete call, ICategories for the categorize call and IMatches for the find call.

  2. cbError This callback is called whenever a backend operation somehow fails to complete. The signature of the callback should be (error: any) => void. The error object could be anything, but should explain the cause of the problem if console.log()'ed or toString()'ed to the page.

It is important to understand that Authentication, Autocomplete, Categorize and Find all have independent callbacks in the configuration. Because of this the success, error and busy-state for each of them can be tracked independently. This means that the query-field may have an indicator somewhere that indicates that it is doing a lookup (if wanted). The categories section may have an indicator to tell that it is working, and finally the results area may also have an indicator telling that results are pending.

Handling user input

In order for the automatic mode to work you need to update the values in your query-field as well as filters and/or sorting order / search-type. This is how the search-client will know when to execute searches/lookups and not.

These are the properties on the SearchClient class that you can manipulate in order to change the query that the search-client is to execute. It is expected that you both set and get them directly:

  • clientId: string
  • dateFrom: DateSpecification
  • dateTo: DateSpecification
  • filters: string[]
  • matchGenerateContent: boolean
  • matchGenerateContentHighlights: boolean
  • matchGrouping: boolean
  • matchOrderBy: OrderBy
  • matchPage: number
  • matchPageSize: number
  • maxSuggestions: number
  • query: Query
  • queryText: string
  • searchType: SearchType
  • uiLanguageCode: string

I.e. searchClient.queryText = "my query"; The normal thing to do is to wire the UI events so that when the user changes the content of the query input field you immediately update the queryText property.

In addition the there are some additional methods that help manage changes in the UI:

Deferring and suppressing registered callbacks

Please note that any of the services' registered callbacks will be called as a part of the fetch-process. This regards to both automatic and manual mode fetches. If you don't want the callbacks to be enabled you have two options:

  1. For the SearchClient: Call deferUpdates(true) before you do anything that would normally trigger callbacks. This will in turn call deferUpdates(true) for all services. When you want callbacks to again be activated, call deferUpdate(false) method. When first param is false it optionally takes a second parameter that can be used to indicate whether pending updates are to be skipped or not.
  2. For a specific service: Call its specific deferUpdates(true) before you do anything that would normally trigger callbacks. And then afterwards, if you want the callbacks to again be active, call deferUpdates(false) and use the second parameter to indicate whether pending updates are to be skipped or not.

Please see SearchClient.deferUpdates for more information.

Authentication

The Haive SearchManager supports two modes of authentication:

  1. Simple JWT based authentication
  2. OpenId Connect based authentication

Both modes are described in details below. If the index is public and does not use authentication then you can turn off authentication (which is enabled by default) by passing this in the settings object in the SearchClient constructor: authentication: { enabled: false }.

JWT Authentication

The Haive SearchManager supports JWT based (JSON Web Token) authentication for differentiating users/permissions. To use this kind of authentication:

  1. The SearchManager must be configured to use the CurrentPrincipal plugin (which then extracts the authentication JWT package).

  2. A web-service that identifies the user must be setup that is accessible from the page that the search-client runs on.

    • The web-service endpoint must identify the user and create a JWT that is returned.
    • On the server-side the JWT needs to be generated by using the same secret key as is set up in the SearchManager (a random key was generated on setup and should be pre-configured).
    • A choice must be made on the expiration time for the token. It is suggested to be liberal, but to still have an expiration time. An hour would probably be fine in many cases.
    • It is suggested that the creation time property in the JWT is backdated with a minute or so to cope for time variances between the SearchManager and this web-service.
  3. The SearchClient authentication settings object must define:

    • Type set to 'jwt'
    • The endpoint url.
    • The path for the jwt value when returned. If the returned structure is { user: { jwt: "actualtokenhash" } } then the tokenPath should be [ "user", "jwt" ].
    • By default

The authentication system, when enabled will attempt to fetch the authentication-token as soon as it is setup (trying to pre-fetch it to have it ready asap in case a search is made).

The authentication system decodes the jwt-token when received and checks for when the token expires. It then sets up a timeout to fetch a new token in ample time before the current one expires. The overlap for this is defined in its triggers: authentication: { triggers: { expiryOverlap: 60 } }. The default is 60 seconds, which means that the client will try to get a new JWT 60 seconds before the old one expires.

Example:

"authentication": { "type": "jwt", "baseUrl": "auth_webservice_url", "servicePath": "auth/login", "enabled": true }

OpenId Connect Authentication

The Haive SearchManager supports OpenId Connect based authentication.

  1. The SearchManager must be configured to use the CurrentPrincipal plugin (which then extracts the authentication JWT package).

  2. A web-service that identifies the user must be setup that is accessible from the page that the search-client runs on.

    • Web service must support standard Open Id Connect flows.
    • Web service must expose discovery endpoint - which should return information like issuer name, key material and supported scopes.
    • The web-service endpoint must identify the user and create access_token for that user.
    • A choice must be made on the expiration time for the token. It is suggested to be liberal, but to still have an expiration time. An hour would probably be fine in many cases.
    • It is suggested that the creation time property in the JWT is backdated with a minute or so to cope for time variances between the SearchManager and this web-service.
  3. The SearchClient authentication settings object must define:

    • Type set to oidc
    • Base url - the url of authority (identity server) supporting Open Id Connect protocol
    • Silent redirect url - the url for redirect in silent token renew operation
    • Redirect url - the url for redirect in login operation
    • Post logout redirect url - the url for redirect in logout operation
    • Service path - path of identity server service
    • Client Id - id of the client registered in identity server
    • Response type - describes response type to be returned by identity server
    • Response mode - describes server response mode ('fragment' for implicit flow, 'query' for authorization code flow)
    • Scopes - list of scopes requested by client
    • Enable logging flag

Implicit flow example:

"authentication": { "type": "oidc", "baseUrl": "localhost:5000", "silentRedirectUri": "localhost:9000/silent.html", "redirectUri": "localhost:9000/callback.html", "postLogoutRedirectUri": "localhost:9000", "servicePath": "", "clientId": "haive.webclient.implicit", "scope": "openid profile", "responseType": "id_token token", "responseMode": "fragment", "enabled": true, "enableLogging": true }

Authorization code flow example:

"authentication": { "type": "oidc", "baseUrl": "localhost:5000", "silentRedirectUri": "localhost:9000/silent.html", "redirectUri": "localhost:9000/callback.html", "postLogoutRedirectUri": "localhost:9000", "servicePath": "", "clientId": "haive.webclient.implicit", "scope": "openid profile", "responseType": "id_token token", "responseMode": "query", "enabled": true, "enableLogging": true }

Example configuration is provided in samples\plain\cfg\search-settings-oidc.js config file.

Documentation / Intellisense / Types

If you are using typescript, then the data-types are available for your IDE to use. If not, then all types and definitions are available in the generated API-documentation in the search-client docs-folder (typically ./node_modules/search-client/docs/index.html).

Generated using TypeDoc