{"id":15044623,"url":"https://github.com/elastic/app-search-node","last_synced_at":"2025-10-28T16:16:36.468Z","repository":{"id":40400761,"uuid":"198666019","full_name":"elastic/app-search-node","owner":"elastic","description":"Elastic App Search Official Node.js Client","archived":false,"fork":false,"pushed_at":"2024-08-08T16:00:30.000Z","size":582,"stargazers_count":45,"open_issues_count":8,"forks_count":24,"subscribers_count":24,"default_branch":"master","last_synced_at":"2025-04-09T15:07:55.052Z","etag":null,"topics":["api-client","elastic","elastic-app-search","javascript","node","search","swiftype"],"latest_commit_sha":null,"homepage":"https://www.elastic.co/products/app-search","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elastic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-24T15:49:38.000Z","updated_at":"2025-01-08T10:26:42.000Z","dependencies_parsed_at":"2024-06-18T16:53:25.990Z","dependency_job_id":"bba754b7-5872-4a56-9797-34127c373b2c","html_url":"https://github.com/elastic/app-search-node","commit_stats":{"total_commits":95,"total_committers":16,"mean_commits":5.9375,"dds":"0.49473684210526314","last_synced_commit":"7c8f794a7ed212688dd3dc870c512d0ec8cc06c8"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elastic%2Fapp-search-node","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elastic%2Fapp-search-node/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elastic%2Fapp-search-node/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elastic%2Fapp-search-node/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elastic","download_url":"https://codeload.github.com/elastic/app-search-node/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248055284,"owners_count":21040157,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-client","elastic","elastic-app-search","javascript","node","search","swiftype"],"created_at":"2024-09-24T20:50:49.054Z","updated_at":"2025-10-28T16:16:31.377Z","avatar_url":"https://github.com/elastic.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e **⚠️ This client is deprecated ⚠️**\n\u003e\n\u003e As of Enterprise Search version 8.3.2, we are directing users to the new [Enterprise Search Node Client](https://github.com/elastic/enterprise-search-js) and\n\u003e deprecating this client.\n\u003e\n\u003e Our development effort on this project will be limited to bug fixes.\n\u003e All future enhancements will be focused on the Enterprise Search Node Client.\n\u003e\n\u003e Thank you! - Elastic\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://github.com/elastic/app-search-node/blob/master/logo-app-search.png?raw=true\" alt=\"Elastic App Search Logo\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\u003ca href=\"https://circleci.com/gh/elastic/app-search-node\"\u003e\u003cimg src=\"https://circleci.com/gh/elastic/app-search-node.svg?style=svg\" alt=\"CircleCI build\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\u003e A first-party Node.JS client for building excellent, relevant search experiences with [Elastic App Search](https://www.elastic.co/products/app-search).\n\n## Contents\n\n- [Getting started](#getting-started-)\n- [Versioning](#versioning)\n- [Usage](#usage)\n- [Running tests](#running-tests)\n- [FAQ](#faq-)\n- [Contribute](#contribute-)\n- [License](#license-)\n\n---\n\n## Getting started 🐣\n\nTo install this package, run:\n\n```bash\nnpm install @elastic/app-search-node\n```\n\n## Versioning\n\nThis client is versioned and released alongside App Search.\n\nTo guarantee compatibility, use the most recent version of this library within the major version of the corresponding App Search implementation.\n\nFor example, for App Search `7.3`, use `7.3` of this library or above, but not `8.0`.\n\nIf you are using the [SaaS version available on swiftype.com](https://app.swiftype.com/as) of App Search, you should use the version 7.5.x of the client.\n\n## Usage\n\n### Setup: Configuring the client and authentication\n\nUsing this client assumes that you have already an instance of [Elastic App Search](https://www.elastic.co/products/app-search) up and running.\n\nThe client is configured using the `baseUrlFn` and `apiKey` parameters.\n\n ```javascript\nconst apiKey = 'private-mu75psc5egt9ppzuycnc2mc3'\nconst baseUrlFn = () =\u003e 'http://localhost:3002/api/as/v1/'\nconst client = new AppSearchClient(undefined, apiKey, baseUrlFn)\n```\n\nNote:\n\nThe `[apiKey]` authenticates requests to the API.\nYou can use any key type with the client, however each has a different scope.\nFor more information on keys, check out the [documentation](https://swiftype.com/documentation/app-search/api/credentials).\n\n#### Swiftype.com App Search users:\n\nWhen using the [SaaS version available on swiftype.com](https://app.swiftype.com/as) of App Search, you can configure the client using your `hostIdentifier` instead of the `baseUrlFn` parameter.\nThe `hostIdentifier` can be found within the [Credentials](https://app.swiftype.com/as#/credentials) menu.\n\n```javascript\nconst AppSearchClient = require('@elastic/app-search-node')\nconst hostIdentifier = 'host-c5s2mj'\nconst apiKey = 'private-mu75psc5egt9ppzuycnc2mc3'\nconst client = new AppSearchClient(hostIdentifier, apiKey)\n```\n\n### API Methods\n\n##### Indexing: Creating or Replacing Documents\n\n```javascript\nconst engineName = 'favorite-videos'\nconst documents = [\n  {\n    id: 'INscMGmhmX4',\n    url: 'https://www.youtube.com/watch?v=INscMGmhmX4',\n    title: 'The Original Grumpy Cat',\n    body: 'A wonderful video of a magnificent cat.'\n  },\n  {\n    id: 'JNDFojsd02',\n    url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',\n    title: 'Another Grumpy Cat',\n    body: 'A great video of another cool cat.'\n  }\n]\n\nclient\n  .indexDocuments(engineName, documents)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error))\n```\n\nNote that this API will not throw on an indexing error. Errors are inlined in the response body per document:\n\n```json\n[\n  { \"id\": \"park_rocky-mountain\", \"errors\": [] },\n  {\n    \"id\": \"park_saguaro\",\n    \"errors\": [\"Invalid field value: Value 'foo' cannot be parsed as a float\"]\n  }\n]\n\n```\n\n##### Indexing: Updating Documents (Partial Updates)\n\n```javascript\nconst engineName = 'favorite-videos'\nconst documents = [\n  {\n    id: 'INscMGmhmX4',\n    title: 'Updated title'\n  }\n]\n\nclient\n  .updateDocuments(engineName, documents)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error))\n```\n\n\n##### Retrieving Documents\n\n```javascript\nconst engineName = 'favorite-videos'\nconst documentIds = ['INscMGmhmX4', 'JNDFojsd02']\n\nclient\n  .getDocuments(engineName, documentIds)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Listing Documents\n\n```javascript\nconst engineName = 'favorite-videos'\n\n// Without paging\nclient\n  .listDocuments(engineName)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n\n// With paging\nclient\n  .listDocuments(engineName, { page: { size: 10, current: 1 } })\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Destroying Documents\n\n```javascript\nconst engineName = 'favorite-videos'\nconst documentIds = ['INscMGmhmX4', 'JNDFojsd02']\n\nclient\n  .destroyDocuments(engineName, documentIds)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Listing Engines\n\n```javascript\nclient\n  .listEngines({ page: { size: 10, current: 1 } })\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Retrieving Engines\n\n```javascript\nconst engineName = 'favorite-videos'\n\nclient\n  .getEngine(engineName)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Creating Engines\n\n```javascript\nconst engineName = 'favorite-videos'\n\nclient\n  .createEngine(engineName, { language: 'en' })\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Destroying Engines\n\n```javascript\nconst engineName = 'favorite-videos'\n\nclient\n  .destroyEngine(engineName)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Searching\n\n```javascript\nconst engineName = 'favorite-videos'\nconst query = 'cat'\nconst searchFields = { title: {} }\nconst resultFields = { title: { raw: {} } }\nconst options = { search_fields: searchFields, result_fields: resultFields }\n\nclient\n  .search(engineName, query, options)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Multi-Search\n\n```javascript\nconst engineName = 'favorite-videos'\nconst searches = [\n  { query: 'cat', options: {\n      search_fields: { title: {} },\n      result_fields: { title: { raw: {} } }\n  } },\n  { query: 'grumpy', options: {} }\n]\n\nclient\n  .multiSearch(engineName, searches)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Query Suggestion\n\n```javascript\nconst engineName = 'favorite-videos'\nconst options = {\n  size: 3,\n  types: {\n    documents: {\n      fields: ['title']\n    }\n  }\n}\n\nclient\n  .querySuggestion(engineName, 'cat', options)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Listing Curations\n\n```javascript\nconst engineName = 'favorite-videos'\n\nclient\n  .listCurations(engineName)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n\n// Pagination details are optional\nconst paginationDetails = {\n        page: {\n          current: 2,\n          size: 10\n        }\n      }\n\nclient\n  .listCurations(engineName, paginationDetails)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Retrieving Curations\n\n```javascript\nconst engineName = 'favorite-videos'\nconst curationId = 'cur-7438290'\n\nclient\n  .getCuration(engineName, curationId)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Creating Curations\n\n```javascript\nconst engineName = 'favorite-videos'\nconst newCuration = {\n  queries: ['cat blop'],\n  promoted: ['Jdas78932'],\n  hidden: ['INscMGmhmX4', 'JNDFojsd02']\n}\n\nclient\n  .createCuration(engineName, newCuration)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Updating Curations\n\n```javascript\nconst engineName = 'favorite-videos'\nconst curationId = 'cur-7438290'\n// \"queries\" is required, either \"promoted\" or \"hidden\" is required.\n// Values sent for all fields will overwrite existing values.\nconst newDetails = {\n  queries: ['cat blop'],\n  promoted: ['Jdas78932', 'JFayf782']\n}\n\nclient\n  .updateCuration(engineName, curationId, newDetails)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Deleting Curations\n\n```javascript\nconst engineName = 'favorite-videos'\nconst curationId = 'cur-7438290'\n\nclient\n  .destroyCuration(engineName, curationId)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Retrieving Schemas\n\n```javascript\nconst engineName = 'favorite-videos'\n\nclient\n  .getSchema(engineName)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Updating Schemas\n\n```javascript\nconst engineName = 'favorite-videos'\nconst schema = {\n  views: 'number',\n  created_at: 'date'\n}\n\nclient\n  .updateSchema(engineName, schema)\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Create a Signed Search Key\n\nCreating a search key that will only return the title field.\n\n```javascript\nconst publicSearchKey = 'search-xxxxxxxxxxxxxxxxxxxxxxxx'\n// This name must match the name of the key above from your App Search dashboard\nconst publicSearchKeyName = 'search-key'\nconst enforcedOptions = {\n  result_fields: { title: { raw: {} } },\n  filters: { world_heritage_site: 'true' }\n}\n\n// Optional. See https://github.com/auth0/node-jsonwebtoken#usage for all options\nconst signOptions = {\n  expiresIn: '5 minutes'\n}\n\nconst signedSearchKey = AppSearchClient.createSignedSearchKey(\n  publicSearchKey,\n  publicSearchKeyName,\n  enforcedOptions,\n  signOptions\n)\n\nconst baseUrlFn = () =\u003e 'http://localhost:3002/api/as/v1/'\nconst client = new AppSearchClient(undefined, signedSearchKey, baseUrlFn)\n\nclient.search('sample-engine', 'everglade')\n```\n\n##### Create a Meta Engine\n\n```javascript\nconst engineName = 'my-meta-engine'\n\nclient\n  .createMetaEngine(engineName, ['source-engine-1', 'source-engine-2'])\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Add a Source Engine to a Meta Engine\n\n```javascript\nconst engineName = 'my-meta-engine'\n\nclient\n  .addMetaEngineSources(engineName, ['source-engine-3'])\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Remove a Source Engine from a Meta Engine\n\n```javascript\nconst engineName = 'my-meta-engine'\n\nclient\n  .deleteMetaEngineSources(engineName, ['source-engine-3'])\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n##### Creating Engines\n\n```javascript\nconst engineName = 'my-meta-engine'\n\nclient\n  .createEngine(engineName, {\n    type: 'meta',\n    source_engines: ['source-engine-1', 'source-engine-2']\n  })\n  .then(response =\u003e console.log(response))\n  .catch(error =\u003e console.log(error.errorMessages))\n```\n\n### For App Search APIs not available in this client\n\nWe try to keep this client up to date with all of the available API endpoints available from App Search.\n\nThere are a few APIs that may not be available yet. For those APIs, please use the low-level client to connect to hit any App Search endpoint.\n\n```javascript\nconst engineName = 'favorite-videos'\nconst options = {\n  query: 'cats'\n}\n\nconst Client = require('@elastic/app-search-node/lib/client')\nconst client = new Client('private-mu75psc5egt9ppzuycnc2mc3', 'http://localhost:3002/api/as/v1/')\nclient.post(`engines/${encodeURIComponent(engineName)}/search`, options).then(console.log)\n```\n\n## Running tests\n\n```bash\nnpm test\n```\n\nThe specs in this project use [node-replay](https://github.com/assaf/node-replay) to capture fixtures.\n\nNew fixtures should be captured from a running instance of App Search.\n\nTo capture new fixtures, run a command like the following:\n\n```\nnvm use\nHOST_IDENTIFIER=host-c5s2mj API_KEY=private-b94wtaoaym2ovdk5dohj3hrz REPLAY=record npm run test -- -g 'should create a meta engine'\n```\n\nTo break that down a little...\n- `HOST_IDENTIFIER` - Use this to override the fake value used in tests with an actual valid value for your App Search instance to record from\n- `API_KEY` - Use this to override the fake value used in tests with an actual valid value for your App Search instance to record from\n- `REPLAY=record` - Tells replay to record a new response if one doesn't already exist\n- `npm run test` - Run the tests\n- `-- -g 'should create a meta engine'` - Limit the tests to ONLY run the new test you've created, 'should create a meta engine' for example\n\nThis will create a new fixture, make sure you manually edit that fixture to replace the host identifier and api key\nrecorded in that fixture with the values the tests use.\n\nYou'll also need to make sure that fixture is located in the correctly named directory under `fixtures` according to the host that was used.\n\nYou'll know if something is not right because this will error when you run `npm run test` with an error like:\n```\nError: POST https://host-c5s2mj.api.swiftype.com:443/api/as/v1/engines refused: not recording and no network access\n```\n\n\n## FAQ 🔮\n\n### Where do I report issues with the client?\n\nIf something is not working as expected, please open an [issue](https://github.com/elastic/app-search-node/issues/new).\n\n### Where can I learn more about App Search?\n\nYour best bet is to read the [documentation](https://swiftype.com/documentation/app-search).\n\n### Where else can I go to get help?\n\nYou can checkout the [Elastic App Search community discuss forums](https://discuss.elastic.co/c/app-search).\n\n## Contribute 🚀\n\nWe welcome contributors to the project. Before you begin, a couple notes...\n\n- Prior to opening a pull request, please create an issue to [discuss the scope of your proposal](https://github.com/elastic/app-search-node/issues).\n- Please write simple code and concise documentation, when appropriate.\n\n## License 📗\n\n[Apache 2.0](https://github.com/elastic/app-search-node/blob/master/LICENSE.txt) © [Elastic](https://github.com/elastic)\n\nThank you to all the [contributors](https://github.com/elastic/app-search-node/graphs/contributors)!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felastic%2Fapp-search-node","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felastic%2Fapp-search-node","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felastic%2Fapp-search-node/lists"}