diff --git a/clients/algoliasearch-client-javascript/bundlesize.config.json b/clients/algoliasearch-client-javascript/bundlesize.config.json index d88e2da745..f327011db6 100644 --- a/clients/algoliasearch-client-javascript/bundlesize.config.json +++ b/clients/algoliasearch-client-javascript/bundlesize.config.json @@ -16,6 +16,10 @@ "path": "packages/client-analytics/dist/builds/browser.umd.js", "maxSize": "4.85KB" }, + { + "path": "packages/client-composition/dist/builds/browser.umd.js", + "maxSize": "4.05KB" + }, { "path": "packages/client-insights/dist/builds/browser.umd.js", "maxSize": "3.90KB" diff --git a/clients/algoliasearch-client-javascript/package.json b/clients/algoliasearch-client-javascript/package.json index bc699a718f..1236d7e995 100644 --- a/clients/algoliasearch-client-javascript/package.json +++ b/clients/algoliasearch-client-javascript/package.json @@ -6,7 +6,7 @@ "packages/*" ], "scripts": { - "build": "lerna run build --scope '@algolia/requester-testing' --scope '@algolia/logger-console' --scope 'algoliasearch' --include-dependencies", + "build": "lerna run build --scope '@algolia/requester-testing' --scope '@algolia/logger-console' --scope 'algoliasearch' --scope '@algolia/client-composition' --include-dependencies", "clean": "lerna run clean", "release:bump": "lerna version ${0:-patch} --no-changelog --no-git-tag-version --no-push --exact --force-publish --yes", "release:publish": "tsc --project scripts/tsconfig.json && node scripts/dist/scripts/publish.js", diff --git a/clients/algoliasearch-client-javascript/packages/client-composition/package.json b/clients/algoliasearch-client-javascript/packages/client-composition/package.json new file mode 100644 index 0000000000..29e1abd5fe --- /dev/null +++ b/clients/algoliasearch-client-javascript/packages/client-composition/package.json @@ -0,0 +1,67 @@ +{ + "version": "0.0.1-alpha.0", + "repository": { + "type": "git", + "url": "git+https://github.com/algolia/algoliasearch-client-javascript.git" + }, + "type": "module", + "license": "MIT", + "author": "Algolia", + "scripts": { + "build": "yarn clean && yarn tsup && yarn rollup -c rollup.config.js", + "clean": "rm -rf ./dist || true", + "test:bundle": "publint . && attw --pack ." + }, + "name": "@algolia/client-composition", + "description": "JavaScript client for client-composition", + "exports": { + ".": { + "node": { + "types": { + "import": "./dist/node.d.ts", + "module": "./dist/node.d.ts", + "require": "./dist/node.d.cts" + }, + "import": "./dist/builds/node.js", + "module": "./dist/builds/node.js", + "require": "./dist/builds/node.cjs" + }, + "worker": { + "types": "./dist/fetch.d.ts", + "default": "./dist/builds/fetch.js" + }, + "default": { + "types": "./dist/browser.d.ts", + "module": "./dist/builds/browser.js", + "import": "./dist/builds/browser.js", + "default": "./dist/builds/browser.umd.js" + } + }, + "./src/*": "./src/*.ts" + }, + "jsdelivr": "./dist/builds/browser.umd.js", + "unpkg": "./dist/builds/browser.umd.js", + "react-native": "./dist/builds/browser.js", + "files": [ + "dist", + "index.js", + "index.d.ts" + ], + "dependencies": { + "@algolia/client-common": "5.12.0", + "@algolia/requester-browser-xhr": "5.12.0", + "@algolia/requester-node-http": "5.12.0", + "@algolia/requester-fetch": "5.12.0" + }, + "devDependencies": { + "@arethetypeswrong/cli": "0.16.4", + "@types/node": "22.8.1", + "publint": "0.2.12", + "rollup": "4.24.2", + "tsup": "8.3.5", + "typescript": "5.6.3" + }, + "engines": { + "node": ">= 14.0.0" + } +} diff --git a/clients/algoliasearch-client-javascript/yarn.lock b/clients/algoliasearch-client-javascript/yarn.lock index d6cb9ccc1b..15a78ced64 100644 --- a/clients/algoliasearch-client-javascript/yarn.lock +++ b/clients/algoliasearch-client-javascript/yarn.lock @@ -54,6 +54,23 @@ __metadata: languageName: unknown linkType: soft +"@algolia/client-composition@workspace:packages/client-composition": + version: 0.0.0-use.local + resolution: "@algolia/client-composition@workspace:packages/client-composition" + dependencies: + "@algolia/client-common": "npm:5.12.0" + "@algolia/requester-browser-xhr": "npm:5.12.0" + "@algolia/requester-fetch": "npm:5.12.0" + "@algolia/requester-node-http": "npm:5.12.0" + "@arethetypeswrong/cli": "npm:0.16.4" + "@types/node": "npm:22.8.1" + publint: "npm:0.2.12" + rollup: "npm:4.24.2" + tsup: "npm:8.3.5" + typescript: "npm:5.6.3" + languageName: unknown + linkType: soft + "@algolia/client-insights@npm:5.12.0, @algolia/client-insights@workspace:packages/client-insights": version: 0.0.0-use.local resolution: "@algolia/client-insights@workspace:packages/client-insights" diff --git a/config/clients.config.json b/config/clients.config.json index 077f521612..24806374df 100644 --- a/config/clients.config.json +++ b/config/clients.config.json @@ -113,12 +113,7 @@ "extension": ".java", "outputFolder": "src/test/java/com/algolia" }, - "supportedVersions": [ - "8", - "11", - "21", - "17" - ] + "supportedVersions": ["8", "11", "21", "17"] }, "javascript": { "clients": [ @@ -161,6 +156,10 @@ { "name": "search", "output": "clients/algoliasearch-client-javascript/packages/client-search" + }, + { + "name": "composition", + "output": "clients/algoliasearch-client-javascript/packages/client-composition" } ], "folder": "clients/algoliasearch-client-javascript", @@ -257,13 +256,7 @@ "extension": ".py", "outputFolder": "" }, - "supportedVersions": [ - "3.8", - "3.9", - "3.10", - "3.11", - "3.12" - ] + "supportedVersions": ["3.8", "3.9", "3.10", "3.11", "3.12"] }, "ruby": { "clients": [ diff --git a/generators/src/main/java/com/algolia/codegen/AlgoliaJavascriptGenerator.java b/generators/src/main/java/com/algolia/codegen/AlgoliaJavascriptGenerator.java index c2d36a6b94..08d05a58f5 100644 --- a/generators/src/main/java/com/algolia/codegen/AlgoliaJavascriptGenerator.java +++ b/generators/src/main/java/com/algolia/codegen/AlgoliaJavascriptGenerator.java @@ -18,6 +18,7 @@ public class AlgoliaJavascriptGenerator extends TypeScriptNodeClientCodegen { private String CLIENT; private boolean isAlgoliasearchClient; + private boolean isAlgoliaCompositionClient; @Override public String getName() { @@ -30,6 +31,7 @@ public void processOpts() { CLIENT = Helpers.camelize((String) additionalProperties.get("client")); isAlgoliasearchClient = CLIENT.equals("algoliasearch"); + isAlgoliaCompositionClient = CLIENT.equals("composition"); // generator specific options setSupportsES6(true); @@ -155,6 +157,7 @@ private void setDefaultGeneratorOptions() { additionalProperties.put("isSearchClient", CLIENT.equals("search") || isAlgoliasearchClient); additionalProperties.put("isIngestionClient", CLIENT.equals("ingestion")); additionalProperties.put("isAlgoliasearchClient", isAlgoliasearchClient); + additionalProperties.put("isAlgoliaCompositionClient", isAlgoliaCompositionClient); additionalProperties.put("packageVersion", Helpers.getPackageJsonVersion(packageName)); additionalProperties.put("packageName", packageName); additionalProperties.put("npmPackageName", isAlgoliasearchClient ? packageName : "@algolia/" + packageName); @@ -169,10 +172,16 @@ private void setDefaultGeneratorOptions() { continue; } + String version = Helpers.getPackageJsonVersion(name); + + if (version.contains("alpha") || version.contains("beta")) { + continue; + } + var dependency = new HashMap(); dependency.put("dependencyName", Helpers.createClientName((String) pkg.get("name"), "javascript")); dependency.put("dependencyPackage", "@algolia/" + name); - dependency.put("dependencyVersion", Helpers.getPackageJsonVersion(name)); + dependency.put("dependencyVersion", version); dependency.put("withInitMethod", !name.contains("search")); dependency.put( "dependencyHasRegionalHosts", diff --git a/generators/src/main/java/com/algolia/codegen/cts/AlgoliaCTSGenerator.java b/generators/src/main/java/com/algolia/codegen/cts/AlgoliaCTSGenerator.java index 82136b24ec..3336e0b3c3 100644 --- a/generators/src/main/java/com/algolia/codegen/cts/AlgoliaCTSGenerator.java +++ b/generators/src/main/java/com/algolia/codegen/cts/AlgoliaCTSGenerator.java @@ -148,6 +148,7 @@ public Map postProcessSupportingFileData(Map obj // We can put whatever we want in the bundle, and it will be accessible in the template bundle.put("mode", mode); bundle.put("is" + Helpers.capitalize(client) + "Client", true); + bundle.put("isStandaloneClient", client.contains("search") || client.equals("composition")); bundle.put("isSearchClient", client.contains("search")); // just so algoliasearch is treated as a search client too bundle.put("client", Helpers.createClientName(importClientName, language) + "Client"); bundle.put("clientPrefix", Helpers.createClientName(importClientName, language)); diff --git a/generators/src/main/java/com/algolia/codegen/cts/manager/JavascriptCTSManager.java b/generators/src/main/java/com/algolia/codegen/cts/manager/JavascriptCTSManager.java index b1be21a8d3..2f81a9854f 100644 --- a/generators/src/main/java/com/algolia/codegen/cts/manager/JavascriptCTSManager.java +++ b/generators/src/main/java/com/algolia/codegen/cts/manager/JavascriptCTSManager.java @@ -46,7 +46,13 @@ public void addDataToBundle(Map bundle) throws GeneratorExceptio bundle.put("utilsPackageVersion", Helpers.getPackageJsonVersion("client-common")); bundle.put("algoliasearchVersion", Helpers.getPackageJsonVersion("algoliasearch")); bundle.put("initMethod", "init" + Helpers.capitalize(Helpers.camelize(client))); - bundle.put("clientName", client.equals("algoliasearch") ? "liteClient" : "algoliasearch"); - bundle.put("importPackage", client.equals("algoliasearch") ? "algoliasearch/lite" : "algoliasearch"); + bundle.put( + "clientName", + client.equals("algoliasearch") ? "liteClient" : client.equals("composition") ? "compositionClient" : "algoliasearch" + ); + bundle.put( + "importPackage", + client.equals("algoliasearch") ? "algoliasearch/lite" : client.equals("composition") ? "@algolia/client-composition" : "algoliasearch" + ); } } diff --git a/playground/javascript/node/composition.ts b/playground/javascript/node/composition.ts new file mode 100644 index 0000000000..d9ec0f7c60 --- /dev/null +++ b/playground/javascript/node/composition.ts @@ -0,0 +1,24 @@ +import { ApiError } from '@algolia/client-common'; +import { compositionClient } from '@algolia/client-composition'; + +const appId = process.env.ALGOLIA_APPLICATION_ID || '**** APP_ID *****'; +const apiKey = process.env.ALGOLIA_ADMIN_KEY || '**** ADMIN_KEY *****'; + +// Init client with appId and apiKey +const client = compositionClient(appId, apiKey); + +async function testComposition() { + try { + const res = await client.listCompositions(); + + console.log(`[OK]`, res); + } catch (e) { + if (e instanceof ApiError) { + return console.log(`[${e.status}] ${e.message}`, e.stackTrace, e); + } + + console.log('[ERROR]', e); + } +} + +testComposition(); diff --git a/playground/javascript/node/package.json b/playground/javascript/node/package.json index b01e37f0eb..e5a2f03fa4 100644 --- a/playground/javascript/node/package.json +++ b/playground/javascript/node/package.json @@ -10,6 +10,7 @@ "@algolia/client-abtesting": "link:../../../clients/algoliasearch-client-javascript/packages/client-abtesting", "@algolia/client-analytics": "link:../../../clients/algoliasearch-client-javascript/packages/client-analytics", "@algolia/client-common": "link:../../../clients/algoliasearch-client-javascript/packages/client-common", + "@algolia/client-composition": "link:../../../clients/algoliasearch-client-javascript/packages/client-composition", "@algolia/client-insights": "link:../../../clients/algoliasearch-client-javascript/packages/client-insights", "@algolia/client-personalization": "link:../../../clients/algoliasearch-client-javascript/packages/client-personalization", "@algolia/client-query-suggestions": "link:../../../clients/algoliasearch-client-javascript/packages/client-query-suggestions", diff --git a/scripts/common.ts b/scripts/common.ts index bc9b83ddc7..8776d6d1c2 100644 --- a/scripts/common.ts +++ b/scripts/common.ts @@ -276,6 +276,10 @@ export async function callGenerator(gen: Generator): Promise { ); } +export function isWSL(): boolean { + return process.env.WSL_DISTRO_NAME !== undefined; +} + export async function setupAndGen( generators: Generator[], mode: GeneratorMode, diff --git a/scripts/cts/testServer/timeout.ts b/scripts/cts/testServer/timeout.ts index 1309dd8c7e..83778ff684 100644 --- a/scripts/cts/testServer/timeout.ts +++ b/scripts/cts/testServer/timeout.ts @@ -17,6 +17,7 @@ export function assertValidTimeouts(expectedCount: number): void { for (const [lang, state] of Object.entries(timeoutState)) { let numberOfTestSuites = 1; + // python has sync and async tests if (lang === 'python') { numberOfTestSuites = 2; } @@ -26,8 +27,8 @@ export function assertValidTimeouts(expectedCount: number): void { expect(state.duration.length).to.equal(3 * numberOfTestSuites); for (let i = 0; i < numberOfTestSuites; i++) { - expect(state.timestamp[3 * i + 1] - state.timestamp[3 * i]).to.be.closeTo(state.duration[3 * i], 100); - expect(state.timestamp[3 * i + 2] - state.timestamp[3 * i + 1]).to.be.closeTo(state.duration[3 * i + 1], 100); + expect(state.timestamp[3 * i + 1] - state.timestamp[3 * i]).to.be.closeTo(state.duration[3 * i], 400); + expect(state.timestamp[3 * i + 2] - state.timestamp[3 * i + 1]).to.be.closeTo(state.duration[3 * i + 1], 400); // languages are not consistent yet for the delay between requests switch (lang) { @@ -35,14 +36,14 @@ export function assertValidTimeouts(expectedCount: number): void { expect(state.duration[3 * i] * 4).to.be.closeTo(state.duration[3 * i + 1], 300); break; case 'php': - expect(state.duration[3 * i] * 2).to.be.closeTo(state.duration[3 * i + 1], 200); + expect(state.duration[3 * i] * 2).to.be.closeTo(state.duration[3 * i + 1], 300); break; case 'swift': expect(state.duration[3 * i]).to.be.closeTo(state.duration[3 * i + 1], 800); break; default: // the delay should be the same, because the `retryCount` is per host instead of global - expect(state.duration[3 * i]).to.be.closeTo(state.duration[3 * i + 1], 150); + expect(state.duration[3 * i]).to.be.closeTo(state.duration[3 * i + 1], 300); break; } } diff --git a/scripts/generate.ts b/scripts/generate.ts index 65dc26141c..9ea4a3a977 100644 --- a/scripts/generate.ts +++ b/scripts/generate.ts @@ -1,4 +1,4 @@ -import { callGenerator, setupAndGen } from './common.js'; +import { callGenerator, isWSL, run, setupAndGen } from './common.js'; import { getLanguageFolder } from './config.js'; import { formatter } from './formatter.js'; import { removeExistingCodegen } from './pre-gen/index.js'; @@ -15,6 +15,9 @@ export async function generate(generators: Generator[]): Promise { }); for (const lang of [...new Set(generators.map((gen) => gen.language))]) { + if (isWSL()) { + await run(`sudo chmod 777 -R ${getLanguageFolder(lang)}`); + } await formatter(lang, getLanguageFolder(lang)); } } diff --git a/specs/common/responses/CompositionNotFound.yml b/specs/common/responses/CompositionNotFound.yml new file mode 100644 index 0000000000..c105e9db04 --- /dev/null +++ b/specs/common/responses/CompositionNotFound.yml @@ -0,0 +1,5 @@ +description: Composition not found. +content: + application/json: + schema: + $ref: '../schemas/ErrorBase.yml' diff --git a/specs/composition/common/parameters.yml b/specs/composition/common/parameters.yml new file mode 100644 index 0000000000..c8a0ba2b88 --- /dev/null +++ b/specs/composition/common/parameters.yml @@ -0,0 +1,11 @@ +compositionID: + in: path + name: compositionID + description: Unique Composition ObjectID. + required: true + schema: + $ref: '#/compositionObjectID' + +compositionObjectID: + type: string + description: Unique Composition ObjectID. diff --git a/specs/composition/common/schemas/Batch.yml b/specs/composition/common/schemas/Batch.yml new file mode 100644 index 0000000000..4883e76ac8 --- /dev/null +++ b/specs/composition/common/schemas/Batch.yml @@ -0,0 +1,6 @@ +action: + type: string + enum: + - upsert + - delete + description: Type of Composition Batch operation. diff --git a/specs/composition/common/schemas/GetTaskResponse.yml b/specs/composition/common/schemas/GetTaskResponse.yml new file mode 100644 index 0000000000..7b4213b832 --- /dev/null +++ b/specs/composition/common/schemas/GetTaskResponse.yml @@ -0,0 +1,8 @@ +title: getTaskResponse +type: object +additionalProperties: false +properties: + status: + $ref: '../../../common/responses/common.yml#/taskStatus' +required: + - status diff --git a/specs/composition/common/schemas/Hit.yml b/specs/composition/common/schemas/Hit.yml new file mode 100644 index 0000000000..2962b8a612 --- /dev/null +++ b/specs/composition/common/schemas/Hit.yml @@ -0,0 +1,43 @@ +hit: + type: object + description: | + Search result. + + A hit is a record from your index, augmented with special attributes for highlighting, snippeting, and ranking. + x-is-generic: true + additionalProperties: true + required: + - objectID + properties: + objectID: + $ref: '../../../common/parameters.yml#/objectID' + _highlightResult: + $ref: '../../../common/schemas/HighlightResult.yml#/highlightResultMap' + _snippetResult: + $ref: '../../../common/schemas/SnippetResult.yml#/snippetResultMap' + _rankingInfo: + $ref: '#/rankingInfo' + _distinctSeqID: + $ref: '../../../common/schemas/Hit.yml#/distinctSeqID' + +rankingInfo: + allOf: + - $ref: '../../../common/schemas/Hit.yml#/rankingInfo' + - $ref: '#/compositionRankingInfo' + +compositionRankingInfo: + type: object + additionalProperties: false + properties: + composed: + title: composedRankingInfo + type: object + additionalProperties: false + properties: + index: + type: string + inset: + type: string + required: + - index + - inset diff --git a/specs/composition/common/schemas/SearchForFacetValuesResponse.yml b/specs/composition/common/schemas/SearchForFacetValuesResponse.yml new file mode 100644 index 0000000000..e44521915e --- /dev/null +++ b/specs/composition/common/schemas/SearchForFacetValuesResponse.yml @@ -0,0 +1,50 @@ +searchForFacetValuesResponse: + type: object + additionalProperties: false + properties: + results: + type: array + description: Search for facet values results. + items: + $ref: '#/searchForFacetValuesResults' + +searchForFacetValuesResults: + type: object + additionalProperties: false + required: + - facetHits + - exhaustiveFacetsCount + - indexName + x-discriminator-fields: + - facetHits + properties: + indexName: + type: string + facetHits: + type: array + description: Matching facet values. + items: + title: facetHits + type: object + additionalProperties: false + required: + - value + - highlighted + - count + properties: + value: + description: Facet value. + example: 'Mobile phone' + type: string + highlighted: + $ref: '../../../common/schemas/HighlightResult.yml#/highlightedValue' + count: + description: Number of records with this facet value. [The count may be approximated](https://support.algolia.com/hc/en-us/articles/4406975248145-Why-are-my-facet-and-hit-counts-not-accurate-). + type: integer + exhaustiveFacetsCount: + type: boolean + description: | + Whether the facet count is exhaustive (true) or approximate (false). + For more information, see [Why are my facet and hit counts not accurate](https://support.algolia.com/hc/en-us/articles/4406975248145-Why-are-my-facet-and-hit-counts-not-accurate-). + processingTimeMS: + $ref: '../../../common/schemas/SearchResponse.yml#/processingTimeMS' diff --git a/specs/composition/common/schemas/SearchParams.yml b/specs/composition/common/schemas/SearchParams.yml new file mode 100644 index 0000000000..42b4171585 --- /dev/null +++ b/specs/composition/common/schemas/SearchParams.yml @@ -0,0 +1,1114 @@ +searchParams: + title: Composition Search parameters as object + type: object + additionalProperties: false + properties: + query: + $ref: '../../../common/schemas/SearchParams.yml#/query' + filters: + $ref: '../../../common/schemas/SearchParams.yml#/filters' + page: + $ref: '../../../common/schemas/SearchParams.yml#/page' + getRankingInfo: + type: boolean + description: Whether the search response should include detailed ranking information. + relevancyStrictness: + type: integer + facetFilters: + $ref: '../../../common/schemas/SearchParams.yml#/facetFilters' + optionalFilters: + $ref: '../../../common/schemas/SearchParams.yml#/optionalFilters' + numericFilters: + $ref: '../../../common/schemas/SearchParams.yml#/numericFilters' + hitsPerPage: + $ref: '../../../common/schemas/IndexSettings.yml#/hitsPerPage' + aroundLatLng: + $ref: '../../../common/schemas/SearchParams.yml#/aroundLatLng' + aroundLatLngViaIP: + $ref: '../../../common/schemas/SearchParams.yml#/aroundLatLngViaIP' + aroundRadius: + $ref: '../../../common/schemas/SearchParams.yml#/aroundRadius' + aroundPrecision: + $ref: '../../../common/schemas/SearchParams.yml#/aroundPrecision' + minimumAroundRadius: + type: integer + description: Minimum radius (in meters) for a search around a location when `aroundRadius` isn't set. + minimum: 1 + x-categories: + - Geo-Search + insideBoundingBox: + $ref: '../../../common/schemas/SearchParams.yml#/insideBoundingBox' + insidePolygon: + $ref: '../../../common/schemas/SearchParams.yml#/insidePolygon' + queryLanguages: + type: array + items: + $ref: '../../../common/schemas/IndexSettings.yml#/supportedLanguage' + example: + - es + description: | + Languages for language-specific query processing steps such as plurals, stop-word removal, and word-detection dictionaries. + + This setting sets a default list of languages used by the `removeStopWords` and `ignorePlurals` settings. + This setting also sets a dictionary for word detection in the logogram-based [CJK](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/normalization/#normalization-for-logogram-based-languages-cjk) languages. + To support this, you must place the CJK language **first**. + + **You should always specify a query language.** + If you don't specify an indexing language, the search engine uses all [supported languages](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/supported-languages/), + or the languages you specified with the `ignorePlurals` or `removeStopWords` parameters. + This can lead to unexpected search results. + For more information, see [Language-specific configuration](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/language-specific-configurations/). + default: [] + x-categories: + - Languages + naturalLanguages: + type: array + items: + $ref: '../../../common/schemas/IndexSettings.yml#/supportedLanguage' + description: | + ISO language codes that adjust settings that are useful for processing natural language queries (as opposed to keyword searches): + + - Sets `removeStopWords` and `ignorePlurals` to the list of provided languages. + - Sets `removeWordsIfNoResults` to `allOptional`. + - Adds a `natural_language` attribute to `ruleContexts` and `analyticsTags`. + default: [] + x-categories: + - Languages + enableRules: + type: boolean + description: Whether to enable rules. + default: true + x-categories: + - Rules + ruleContexts: + type: array + items: + type: string + description: | + Assigns a rule context to the search query. + + [Rule contexts](https://www.algolia.com/doc/guides/managing-results/rules/rules-overview/how-to/customize-search-results-by-platform/#whats-a-context) are strings that you can use to trigger matching rules. + default: [] + example: [mobile] + x-categories: + - Rules + userToken: + $ref: '../../../common/schemas/SearchParams.yml#/userToken' + clickAnalytics: + type: boolean + description: | + Whether to include a `queryID` attribute in the response. + + The query ID is a unique identifier for a search query and is required for tracking [click and conversion events](https://www.algolia.com/guides/sending-events/getting-started/). + default: false + x-categories: + - Analytics + analytics: + type: boolean + description: Whether this search will be included in Analytics. + default: true + x-categories: + - Analytics + analyticsTags: + type: array + items: + type: string + description: Tags to apply to the query for [segmenting analytics data](https://www.algolia.com/doc/guides/search-analytics/guides/segments/). + default: [] + x-categories: + - Analytics + enableABTest: + type: boolean + description: Whether to enable A/B testing for this search. + default: true + x-categories: + - Advanced + enableReRanking: + type: boolean + description: | + Whether this search will use [Dynamic Re-Ranking](https://www.algolia.com/doc/guides/algolia-ai/re-ranking/). + + This setting only has an effect if you activated Dynamic Re-Ranking for this index in the Algolia dashboard. + default: true + x-categories: + - Filtering + +mainInjectionQueryParameters: + title: Composition Main Injection Query parameters as object + type: object + additionalProperties: false + properties: + attributesToRetrieve: + type: array + items: + type: string + example: + - author + - title + - content + description: | + Attributes to include in the API response. + + To reduce the size of your response, you can retrieve only some of the attributes. + Attribute names are case-sensitive. + + - `*` retrieves all attributes, except attributes included in the `customRanking` and `unretrievableAttributes` settings. + - To retrieve all attributes except a specific one, prefix the attribute with a dash and combine it with the `*`: `["*", "-ATTRIBUTE"]`. + - The `objectID` attribute is always included. + default: ['*'] + x-categories: + - Attributes + restrictSearchableAttributes: + type: array + items: + type: string + example: [title, author] + description: | + Restricts a search to a subset of your searchable attributes. + Attribute names are case-sensitive. + default: [] + x-categories: + - Filtering + filters: + $ref: '../../../common/schemas/SearchParams.yml#/filters' + facetFilters: + $ref: '../../../common/schemas/SearchParams.yml#/facetFilters' + optionalFilters: + $ref: '../../../common/schemas/SearchParams.yml#/optionalFilters' + numericFilters: + $ref: '../../../common/schemas/SearchParams.yml#/numericFilters' + sumOrFiltersScores: + type: boolean + description: | + Whether to sum all filter scores. + + If true, all filter scores are summed. + Otherwise, the maximum filter score is kept. + For more information, see [filter scores](https://www.algolia.com/doc/guides/managing-results/refine-results/filtering/in-depth/filter-scoring/#accumulating-scores-with-sumorfiltersscores). + default: false + x-categories: + - Filtering + facets: + type: array + items: + type: string + description: | + Facets for which to retrieve facet values that match the search criteria and the number of matching facet values. + + To retrieve all facets, use the wildcard character `*`. + For more information, see [facets](https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/#contextual-facet-values-and-counts). + default: [] + example: ['*'] + x-categories: + - Faceting + maxValuesPerFacet: + type: integer + description: Maximum number of facet values to return for each facet. + default: 100 + maximum: 1000 + x-categories: + - Faceting + facetingAfterDistinct: + type: boolean + description: | + Whether faceting should be applied after deduplication with `distinct`. + + This leads to accurate facet counts when using faceting in combination with `distinct`. + It's usually better to use `afterDistinct` modifiers in the `attributesForFaceting` setting, + as `facetingAfterDistinct` only computes correct facet counts if all records have the same facet values for the `attributeForDistinct`. + default: false + x-categories: + - Faceting + sortFacetValuesBy: + type: string + description: | + Order in which to retrieve facet values. + + - `count`. + Facet values are retrieved by decreasing count. + The count is the number of matching records containing this facet value. + + - `alpha`. + Retrieve facet values alphabetically. + + This setting doesn't influence how facet values are displayed in your UI (see `renderingContent`). + For more information, see [facet value display](https://www.algolia.com/doc/guides/building-search-ui/ui-and-ux-patterns/facet-display/js/). + default: count + x-categories: + - Faceting + attributesToHighlight: + type: array + items: + type: string + example: [author, title, conten, content] + description: | + Attributes to highlight. + + By default, all searchable attributes are highlighted. + Use `*` to highlight all attributes or use an empty array `[]` to turn off highlighting. + Attribute names are case-sensitive. + + With highlighting, strings that match the search query are surrounded by HTML tags defined by `highlightPreTag` and `highlightPostTag`. + You can use this to visually highlight matching parts of a search query in your UI. + + For more information, see [Highlighting and snippeting](https://www.algolia.com/doc/guides/building-search-ui/ui-and-ux-patterns/highlighting-snippeting/js/). + x-categories: + - Highlighting and Snippeting + attributesToSnippet: + type: array + items: + type: string + example: + - content:80 + - description + description: | + Attributes for which to enable snippets. + Attribute names are case-sensitive. + + Snippets provide additional context to matched words. + If you enable snippets, they include 10 words, including the matched word. + The matched word will also be wrapped by HTML tags for highlighting. + You can adjust the number of words with the following notation: `ATTRIBUTE:NUMBER`, + where `NUMBER` is the number of words to be extracted. + default: [] + x-categories: + - Highlighting and Snippeting + highlightPreTag: + type: string + description: HTML tag to insert before the highlighted parts in all highlighted results and snippets. + default: + x-categories: + - Highlighting and Snippeting + highlightPostTag: + type: string + description: HTML tag to insert after the highlighted parts in all highlighted results and snippets. + default: + x-categories: + - Highlighting and Snippeting + snippetEllipsisText: + type: string + description: String used as an ellipsis indicator when a snippet is truncated. + default: … + x-categories: + - Highlighting and Snippeting + restrictHighlightAndSnippetArrays: + type: boolean + description: | + Whether to restrict highlighting and snippeting to items that at least partially matched the search query. + By default, all items are highlighted and snippeted. + default: false + x-categories: + - Highlighting and Snippeting + hitsPerPage: + $ref: '../../../common/schemas/IndexSettings.yml#/hitsPerPage' + length: + type: integer + description: Number of hits to retrieve (used in combination with `offset`). + minimum: 0 + maximum: 1000 + x-categories: + - Pagination + minWordSizefor1Typo: + type: integer + description: Minimum number of characters a word in the search query must contain to accept matches with [one typo](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/typo-tolerance/in-depth/configuring-typo-tolerance/#configuring-word-length-for-typos). + default: 4 + x-categories: + - Typos + minWordSizefor2Typos: + type: integer + description: Minimum number of characters a word in the search query must contain to accept matches with [two typos](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/typo-tolerance/in-depth/configuring-typo-tolerance/#configuring-word-length-for-typos). + default: 8 + x-categories: + - Typos + typoTolerance: + $ref: '../../../common/schemas/IndexSettings.yml#/typoTolerance' + allowTyposOnNumericTokens: + type: boolean + description: | + Whether to allow typos on numbers in the search query. + + Turn off this setting to reduce the number of irrelevant matches + when searching in large sets of similar numbers. + default: true + x-categories: + - Typos + disableTypoToleranceOnAttributes: + type: array + items: + type: string + example: + - sku + description: | + Attributes for which you want to turn off [typo tolerance](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/typo-tolerance/). + Attribute names are case-sensitive. + + Returning only exact matches can help when: + + - [Searching in hyphenated attributes](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/typo-tolerance/how-to/how-to-search-in-hyphenated-attributes/). + - Reducing the number of matches when you have too many. + This can happen with attributes that are long blocks of text, such as product descriptions. + + Consider alternatives such as `disableTypoToleranceOnWords` or adding synonyms if your attributes have intentional unusual spellings that might look like typos. + default: [] + x-categories: + - Typos + ignorePlurals: + $ref: '../../../common/schemas/IndexSettings.yml#/ignorePlurals' + removeStopWords: + $ref: '../../../common/schemas/IndexSettings.yml#/removeStopWords' + queryLanguages: + type: array + items: + $ref: '../../../common/schemas/IndexSettings.yml#/supportedLanguage' + example: + - es + description: | + Languages for language-specific query processing steps such as plurals, stop-word removal, and word-detection dictionaries. + + This setting sets a default list of languages used by the `removeStopWords` and `ignorePlurals` settings. + This setting also sets a dictionary for word detection in the logogram-based [CJK](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/normalization/#normalization-for-logogram-based-languages-cjk) languages. + To support this, you must place the CJK language **first**. + + **You should always specify a query language.** + If you don't specify an indexing language, the search engine uses all [supported languages](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/supported-languages/), + or the languages you specified with the `ignorePlurals` or `removeStopWords` parameters. + This can lead to unexpected search results. + For more information, see [Language-specific configuration](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/language-specific-configurations/). + default: [] + x-categories: + - Languages + naturalLanguages: + type: array + items: + $ref: '../../../common/schemas/IndexSettings.yml#/supportedLanguage' + description: | + ISO language codes that adjust settings that are useful for processing natural language queries (as opposed to keyword searches): + + - Sets `removeStopWords` and `ignorePlurals` to the list of provided languages. + - Sets `removeWordsIfNoResults` to `allOptional`. + - Adds a `natural_language` attribute to `ruleContexts` and `analyticsTags`. + default: [] + x-categories: + - Languages + decompoundQuery: + type: boolean + description: | + Whether to split compound words in the query into their building blocks. + + For more information, see [Word segmentation](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/language-specific-configurations/#splitting-compound-words). + Word segmentation is supported for these languages: German, Dutch, Finnish, Swedish, and Norwegian. + Decompounding doesn't work for words with [non-spacing mark Unicode characters](https://www.charactercodes.net/category/non-spacing_mark). + For example, `Gartenstühle` won't be decompounded if the `ü` consists of `u` (U+0075) and `◌̈` (U+0308). + default: true + x-categories: + - Languages + enableRules: + type: boolean + description: Whether to enable rules. + default: true + x-categories: + - Rules + ruleContexts: + type: array + items: + type: string + description: | + Assigns a rule context to the search query. + + [Rule contexts](https://www.algolia.com/doc/guides/managing-results/rules/rules-overview/how-to/customize-search-results-by-platform/#whats-a-context) are strings that you can use to trigger matching rules. + default: [] + example: [mobile] + x-categories: + - Rules + enablePersonalization: + type: boolean + description: Whether to enable Personalization. + default: false + x-categories: + - Personalization + personalizationImpact: + type: integer + description: | + Impact that Personalization should have on this search. + + The higher this value is, the more Personalization determines the ranking compared to other factors. + For more information, see [Understanding Personalization impact](https://www.algolia.com/doc/guides/personalization/personalizing-results/in-depth/configuring-personalization/#understanding-personalization-impact). + default: 100 + minimum: 0 + maximum: 100 + x-categories: + - Personalization + queryType: + $ref: '../../../common/schemas/IndexSettings.yml#/queryType' + removeWordsIfNoResults: + $ref: '../../../common/schemas/IndexSettings.yml#/removeWordsIfNoResults' + advancedSyntax: + type: boolean + description: | + Whether to support phrase matching and excluding words from search queries. + + Use the `advancedSyntaxFeatures` parameter to control which feature is supported. + default: false + x-categories: + - Query strategy + optionalWords: + type: array + items: + type: string + example: + - blue + - iphone case + description: | + Words that should be considered optional when found in the query. + + By default, records must match all words in the search query to be included in the search results. + Adding optional words can help to increase the number of search results by running an additional search query that doesn't include the optional words. + For example, if the search query is "action video" and "video" is an optional word, + the search engine runs two queries. One for "action video" and one for "action". + Records that match all words are ranked higher. + + For a search query with 4 or more words **and** all its words are optional, + the number of matched words required for a record to be included in the search results increases for every 1,000 records: + + - If `optionalWords` has less than 10 words, the required number of matched words increases by 1: + results 1 to 1,000 require 1 matched word, results 1,001 to 2000 need 2 matched words. + - If `optionalWords` has 10 or more words, the number of required matched words increases by the number of optional words divided by 5 (rounded down). + For example, with 18 optional words: results 1 to 1,000 require 1 matched word, results 1,001 to 2000 need 4 matched words. + + For more information, see [Optional words](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/empty-or-insufficient-results/#creating-a-list-of-optional-words). + default: [] + x-categories: + - Query strategy + disableExactOnAttributes: + type: array + items: + type: string + example: + - description + description: | + Searchable attributes for which you want to [turn off the Exact ranking criterion](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/override-search-engine-defaults/in-depth/adjust-exact-settings/#turn-off-exact-for-some-attributes). + Attribute names are case-sensitive. + + This can be useful for attributes with long values, where the likelihood of an exact match is high, + such as product descriptions. + Turning off the Exact ranking criterion for these attributes favors exact matching on other attributes. + This reduces the impact of individual attributes with a lot of content on ranking. + default: [] + x-categories: + - Query strategy + exactOnSingleWordQuery: + $ref: '../../../common/schemas/IndexSettings.yml#/exactOnSingleWordQuery' + alternativesAsExact: + type: array + items: + $ref: '../../../common/schemas/IndexSettings.yml#/alternativesAsExact' + description: | + Determine which plurals and synonyms should be considered an exact matches. + + By default, Algolia treats singular and plural forms of a word, and single-word synonyms, as [exact](https://www.algolia.com/doc/guides/managing-results/relevance-overview/in-depth/ranking-criteria/#exact) matches when searching. + For example: + + - "swimsuit" and "swimsuits" are treated the same + - "swimsuit" and "swimwear" are treated the same (if they are [synonyms](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/adding-synonyms/#regular-synonyms)). + + - `ignorePlurals`. + Plurals and similar declensions added by the `ignorePlurals` setting are considered exact matches. + + - `singleWordSynonym`. + Single-word synonyms, such as "NY" = "NYC", are considered exact matches. + + - `multiWordsSynonym`. + Multi-word synonyms, such as "NY" = "New York", are considered exact matches. + default: [ignorePlurals, singleWordSynonym] + x-categories: + - Query strategy + advancedSyntaxFeatures: + type: array + items: + $ref: '../../../common/schemas/IndexSettings.yml#/advancedSyntaxFeatures' + description: | + Advanced search syntax features you want to support. + + - `exactPhrase`. + Phrases in quotes must match exactly. + For example, `sparkly blue "iPhone case"` only returns records with the exact string "iPhone case". + + - `excludeWords`. + Query words prefixed with a `-` must not occur in a record. + For example, `search -engine` matches records that contain "search" but not "engine". + + This setting only has an effect if `advancedSyntax` is true. + default: [exactPhrase, excludeWords] + x-categories: + - Query strategy + distinct: + $ref: '../../../common/schemas/IndexSettings.yml#/distinct' + getRankingInfo: + type: boolean + description: Whether the search response should include detailed ranking information. + clickAnalytics: + type: boolean + description: | + Whether to include a `queryID` attribute in the response. + + The query ID is a unique identifier for a search query and is required for tracking [click and conversion events](https://www.algolia.com/guides/sending-events/getting-started/). + default: false + x-categories: + - Analytics + analytics: + type: boolean + description: Whether this search will be included in Analytics. + default: true + x-categories: + - Analytics + analyticsTags: + type: array + items: + type: string + description: Tags to apply to the query for [segmenting analytics data](https://www.algolia.com/doc/guides/search-analytics/guides/segments/). + default: [] + x-categories: + - Analytics + synonyms: + type: boolean + description: Whether to take into account an index's synonyms for this search. + default: true + x-categories: + - Advanced + replaceSynonymsInHighlight: + type: boolean + description: | + Whether to replace a highlighted word with the matched synonym. + + By default, the original words are highlighted even if a synonym matches. + For example, with `home` as a synonym for `house` and a search for `home`, + records matching either "home" or "house" are included in the search results, + and either "home" or "house" are highlighted. + + With `replaceSynonymsInHighlight` set to `true`, a search for `home` still matches the same records, + but all occurrences of "house" are replaced by "home" in the highlighted response. + default: false + x-categories: + - Highlighting and Snippeting + minProximity: + type: integer + minimum: 1 + maximum: 7 + description: | + Minimum proximity score for two matching words. + + This adjusts the [Proximity ranking criterion](https://www.algolia.com/doc/guides/managing-results/relevance-overview/in-depth/ranking-criteria/#proximity) + by equally scoring matches that are farther apart. + + For example, if `minProximity` is 2, neighboring matches and matches with one word between them would have the same score. + default: 1 + x-categories: + - Advanced + responseFields: + type: array + items: + type: string + description: | + Properties to include in the API response of `search` and `browse` requests. + + By default, all response properties are included. + To reduce the response size, you can select, which attributes should be included. + + You can't exclude these properties: + `message`, `warning`, `cursor`, `serverUsed`, `indexUsed`, + `abTestVariantID`, `parsedQuery`, or any property triggered by the `getRankingInfo` parameter. + + Don't exclude properties that you might need in your search UI. + default: ['*'] + x-categories: + - Advanced + maxFacetHits: + $ref: '../../../common/schemas/IndexSettings.yml#/maxFacetHits' + percentileComputation: + type: boolean + description: Whether to include this search when calculating processing-time percentiles. + default: true + x-categories: + - Advanced + attributeCriteriaComputedByMinProximity: + type: boolean + description: | + Whether the best matching attribute should be determined by minimum proximity. + + This setting only affects ranking if the Attribute ranking criterion comes before Proximity in the `ranking` setting. + If true, the best matching attribute is selected based on the minimum proximity of multiple matches. + Otherwise, the best matching attribute is determined by the order in the `searchableAttributes` setting. + default: false + x-categories: + - Advanced + enableABTest: + type: boolean + description: Whether to enable A/B testing for this search. + default: true + x-categories: + - Advanced + enableReRanking: + type: boolean + description: | + Whether this search will use [Dynamic Re-Ranking](https://www.algolia.com/doc/guides/algolia-ai/re-ranking/). + + This setting only has an effect if you activated Dynamic Re-Ranking for this index in the Algolia dashboard. + default: true + x-categories: + - Filtering + +InsetsQueryParameters: + title: Composition Insets Query parameters as object + type: object + additionalProperties: false + properties: + attributesToRetrieve: + type: array + items: + type: string + example: + - author + - title + - content + description: | + Attributes to include in the API response. + + To reduce the size of your response, you can retrieve only some of the attributes. + Attribute names are case-sensitive. + + - `*` retrieves all attributes, except attributes included in the `customRanking` and `unretrievableAttributes` settings. + - To retrieve all attributes except a specific one, prefix the attribute with a dash and combine it with the `*`: `["*", "-ATTRIBUTE"]`. + - The `objectID` attribute is always included. + default: ['*'] + x-categories: + - Attributes + restrictSearchableAttributes: + type: array + items: + type: string + example: [title, author] + description: | + Restricts a search to a subset of your searchable attributes. + Attribute names are case-sensitive. + default: [] + x-categories: + - Filtering + filters: + $ref: '../../../common/schemas/SearchParams.yml#/filters' + facetFilters: + $ref: '../../../common/schemas/SearchParams.yml#/facetFilters' + optionalFilters: + $ref: '../../../common/schemas/SearchParams.yml#/optionalFilters' + numericFilters: + $ref: '../../../common/schemas/SearchParams.yml#/numericFilters' + attributesToHighlight: + type: array + items: + type: string + example: [author, title, conten, content] + description: | + Attributes to highlight. + + By default, all searchable attributes are highlighted. + Use `*` to highlight all attributes or use an empty array `[]` to turn off highlighting. + Attribute names are case-sensitive. + + With highlighting, strings that match the search query are surrounded by HTML tags defined by `highlightPreTag` and `highlightPostTag`. + You can use this to visually highlight matching parts of a search query in your UI. + + For more information, see [Highlighting and snippeting](https://www.algolia.com/doc/guides/building-search-ui/ui-and-ux-patterns/highlighting-snippeting/js/). + x-categories: + - Highlighting and Snippeting + attributesToSnippet: + type: array + items: + type: string + example: + - content:80 + - description + description: | + Attributes for which to enable snippets. + Attribute names are case-sensitive. + + Snippets provide additional context to matched words. + If you enable snippets, they include 10 words, including the matched word. + The matched word will also be wrapped by HTML tags for highlighting. + You can adjust the number of words with the following notation: `ATTRIBUTE:NUMBER`, + where `NUMBER` is the number of words to be extracted. + default: [] + x-categories: + - Highlighting and Snippeting + highlightPreTag: + type: string + description: HTML tag to insert before the highlighted parts in all highlighted results and snippets. + default: + x-categories: + - Highlighting and Snippeting + highlightPostTag: + type: string + description: HTML tag to insert after the highlighted parts in all highlighted results and snippets. + default: + x-categories: + - Highlighting and Snippeting + snippetEllipsisText: + type: string + description: String used as an ellipsis indicator when a snippet is truncated. + default: … + x-categories: + - Highlighting and Snippeting + restrictHighlightAndSnippetArrays: + type: boolean + description: | + Whether to restrict highlighting and snippeting to items that at least partially matched the search query. + By default, all items are highlighted and snippeted. + default: false + x-categories: + - Highlighting and Snippeting + minWordSizefor1Typo: + type: integer + description: Minimum number of characters a word in the search query must contain to accept matches with [one typo](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/typo-tolerance/in-depth/configuring-typo-tolerance/#configuring-word-length-for-typos). + default: 4 + x-categories: + - Typos + minWordSizefor2Typos: + type: integer + description: Minimum number of characters a word in the search query must contain to accept matches with [two typos](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/typo-tolerance/in-depth/configuring-typo-tolerance/#configuring-word-length-for-typos). + default: 8 + x-categories: + - Typos + typoTolerance: + $ref: '../../../common/schemas/IndexSettings.yml#/typoTolerance' + allowTyposOnNumericTokens: + type: boolean + description: | + Whether to allow typos on numbers in the search query. + + Turn off this setting to reduce the number of irrelevant matches + when searching in large sets of similar numbers. + default: true + x-categories: + - Typos + disableTypoToleranceOnAttributes: + type: array + items: + type: string + example: + - sku + description: | + Attributes for which you want to turn off [typo tolerance](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/typo-tolerance/). + Attribute names are case-sensitive. + + Returning only exact matches can help when: + + - [Searching in hyphenated attributes](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/typo-tolerance/how-to/how-to-search-in-hyphenated-attributes/). + - Reducing the number of matches when you have too many. + This can happen with attributes that are long blocks of text, such as product descriptions. + + Consider alternatives such as `disableTypoToleranceOnWords` or adding synonyms if your attributes have intentional unusual spellings that might look like typos. + default: [] + x-categories: + - Typos + ignorePlurals: + $ref: '../../../common/schemas/IndexSettings.yml#/ignorePlurals' + removeStopWords: + $ref: '../../../common/schemas/IndexSettings.yml#/removeStopWords' + queryLanguages: + type: array + items: + $ref: '../../../common/schemas/IndexSettings.yml#/supportedLanguage' + example: + - es + description: | + Languages for language-specific query processing steps such as plurals, stop-word removal, and word-detection dictionaries. + + This setting sets a default list of languages used by the `removeStopWords` and `ignorePlurals` settings. + This setting also sets a dictionary for word detection in the logogram-based [CJK](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/normalization/#normalization-for-logogram-based-languages-cjk) languages. + To support this, you must place the CJK language **first**. + + **You should always specify a query language.** + If you don't specify an indexing language, the search engine uses all [supported languages](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/supported-languages/), + or the languages you specified with the `ignorePlurals` or `removeStopWords` parameters. + This can lead to unexpected search results. + For more information, see [Language-specific configuration](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/language-specific-configurations/). + default: [] + x-categories: + - Languages + naturalLanguages: + type: array + items: + $ref: '../../../common/schemas/IndexSettings.yml#/supportedLanguage' + description: | + ISO language codes that adjust settings that are useful for processing natural language queries (as opposed to keyword searches): + + - Sets `removeStopWords` and `ignorePlurals` to the list of provided languages. + - Sets `removeWordsIfNoResults` to `allOptional`. + - Adds a `natural_language` attribute to `ruleContexts` and `analyticsTags`. + default: [] + x-categories: + - Languages + decompoundQuery: + type: boolean + description: | + Whether to split compound words in the query into their building blocks. + + For more information, see [Word segmentation](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/language-specific-configurations/#splitting-compound-words). + Word segmentation is supported for these languages: German, Dutch, Finnish, Swedish, and Norwegian. + Decompounding doesn't work for words with [non-spacing mark Unicode characters](https://www.charactercodes.net/category/non-spacing_mark). + For example, `Gartenstühle` won't be decompounded if the `ü` consists of `u` (U+0075) and `◌̈` (U+0308). + default: true + x-categories: + - Languages + enableRules: + type: boolean + description: Whether to enable rules. + default: true + x-categories: + - Rules + ruleContexts: + type: array + items: + type: string + description: | + Assigns a rule context to the search query. + + [Rule contexts](https://www.algolia.com/doc/guides/managing-results/rules/rules-overview/how-to/customize-search-results-by-platform/#whats-a-context) are strings that you can use to trigger matching rules. + default: [] + example: [mobile] + x-categories: + - Rules + enablePersonalization: + type: boolean + description: Whether to enable Personalization. + default: false + x-categories: + - Personalization + personalizationImpact: + type: integer + description: | + Impact that Personalization should have on this search. + + The higher this value is, the more Personalization determines the ranking compared to other factors. + For more information, see [Understanding Personalization impact](https://www.algolia.com/doc/guides/personalization/personalizing-results/in-depth/configuring-personalization/#understanding-personalization-impact). + default: 100 + minimum: 0 + maximum: 100 + x-categories: + - Personalization + queryType: + $ref: '../../../common/schemas/IndexSettings.yml#/queryType' + removeWordsIfNoResults: + $ref: '../../../common/schemas/IndexSettings.yml#/removeWordsIfNoResults' + advancedSyntax: + type: boolean + description: | + Whether to support phrase matching and excluding words from search queries. + + Use the `advancedSyntaxFeatures` parameter to control which feature is supported. + default: false + x-categories: + - Query strategy + optionalWords: + type: array + items: + type: string + example: + - blue + - iphone case + description: | + Words that should be considered optional when found in the query. + + By default, records must match all words in the search query to be included in the search results. + Adding optional words can help to increase the number of search results by running an additional search query that doesn't include the optional words. + For example, if the search query is "action video" and "video" is an optional word, + the search engine runs two queries. One for "action video" and one for "action". + Records that match all words are ranked higher. + + For a search query with 4 or more words **and** all its words are optional, + the number of matched words required for a record to be included in the search results increases for every 1,000 records: + + - If `optionalWords` has less than 10 words, the required number of matched words increases by 1: + results 1 to 1,000 require 1 matched word, results 1,001 to 2000 need 2 matched words. + - If `optionalWords` has 10 or more words, the number of required matched words increases by the number of optional words divided by 5 (rounded down). + For example, with 18 optional words: results 1 to 1,000 require 1 matched word, results 1,001 to 2000 need 4 matched words. + + For more information, see [Optional words](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/empty-or-insufficient-results/#creating-a-list-of-optional-words). + default: [] + x-categories: + - Query strategy + disableExactOnAttributes: + type: array + items: + type: string + example: + - description + description: | + Searchable attributes for which you want to [turn off the Exact ranking criterion](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/override-search-engine-defaults/in-depth/adjust-exact-settings/#turn-off-exact-for-some-attributes). + Attribute names are case-sensitive. + + This can be useful for attributes with long values, where the likelihood of an exact match is high, + such as product descriptions. + Turning off the Exact ranking criterion for these attributes favors exact matching on other attributes. + This reduces the impact of individual attributes with a lot of content on ranking. + default: [] + x-categories: + - Query strategy + exactOnSingleWordQuery: + $ref: '../../../common/schemas/IndexSettings.yml#/exactOnSingleWordQuery' + alternativesAsExact: + type: array + items: + $ref: '../../../common/schemas/IndexSettings.yml#/alternativesAsExact' + description: | + Determine which plurals and synonyms should be considered an exact matches. + + By default, Algolia treats singular and plural forms of a word, and single-word synonyms, as [exact](https://www.algolia.com/doc/guides/managing-results/relevance-overview/in-depth/ranking-criteria/#exact) matches when searching. + For example: + + - "swimsuit" and "swimsuits" are treated the same + - "swimsuit" and "swimwear" are treated the same (if they are [synonyms](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/adding-synonyms/#regular-synonyms)). + + - `ignorePlurals`. + Plurals and similar declensions added by the `ignorePlurals` setting are considered exact matches. + + - `singleWordSynonym`. + Single-word synonyms, such as "NY" = "NYC", are considered exact matches. + + - `multiWordsSynonym`. + Multi-word synonyms, such as "NY" = "New York", are considered exact matches. + default: [ignorePlurals, singleWordSynonym] + x-categories: + - Query strategy + advancedSyntaxFeatures: + type: array + items: + $ref: '../../../common/schemas/IndexSettings.yml#/advancedSyntaxFeatures' + description: | + Advanced search syntax features you want to support. + + - `exactPhrase`. + Phrases in quotes must match exactly. + For example, `sparkly blue "iPhone case"` only returns records with the exact string "iPhone case". + + - `excludeWords`. + Query words prefixed with a `-` must not occur in a record. + For example, `search -engine` matches records that contain "search" but not "engine". + + This setting only has an effect if `advancedSyntax` is true. + default: [exactPhrase, excludeWords] + x-categories: + - Query strategy + distinct: + $ref: '../../../common/schemas/IndexSettings.yml#/distinct' + getRankingInfo: + type: boolean + description: Whether the search response should include detailed ranking information. + clickAnalytics: + type: boolean + description: | + Whether to include a `queryID` attribute in the response. + + The query ID is a unique identifier for a search query and is required for tracking [click and conversion events](https://www.algolia.com/guides/sending-events/getting-started/). + default: false + x-categories: + - Analytics + analytics: + type: boolean + description: Whether this search will be included in Analytics. + default: true + x-categories: + - Analytics + analyticsTags: + type: array + items: + type: string + description: Tags to apply to the query for [segmenting analytics data](https://www.algolia.com/doc/guides/search-analytics/guides/segments/). + default: [] + x-categories: + - Analytics + synonyms: + type: boolean + description: Whether to take into account an index's synonyms for this search. + default: true + x-categories: + - Advanced + replaceSynonymsInHighlight: + type: boolean + description: | + Whether to replace a highlighted word with the matched synonym. + + By default, the original words are highlighted even if a synonym matches. + For example, with `home` as a synonym for `house` and a search for `home`, + records matching either "home" or "house" are included in the search results, + and either "home" or "house" are highlighted. + + With `replaceSynonymsInHighlight` set to `true`, a search for `home` still matches the same records, + but all occurrences of "house" are replaced by "home" in the highlighted response. + default: false + x-categories: + - Highlighting and Snippeting + minProximity: + type: integer + minimum: 1 + maximum: 7 + description: | + Minimum proximity score for two matching words. + + This adjusts the [Proximity ranking criterion](https://www.algolia.com/doc/guides/managing-results/relevance-overview/in-depth/ranking-criteria/#proximity) + by equally scoring matches that are farther apart. + + For example, if `minProximity` is 2, neighboring matches and matches with one word between them would have the same score. + default: 1 + x-categories: + - Advanced + responseFields: + type: array + items: + type: string + description: | + Properties to include in the API response of `search` and `browse` requests. + + By default, all response properties are included. + To reduce the response size, you can select, which attributes should be included. + + You can't exclude these properties: + `message`, `warning`, `cursor`, `serverUsed`, `indexUsed`, + `abTestVariantID`, `parsedQuery`, or any property triggered by the `getRankingInfo` parameter. + + Don't exclude properties that you might need in your search UI. + default: ['*'] + x-categories: + - Advanced + maxFacetHits: + $ref: '../../../common/schemas/IndexSettings.yml#/maxFacetHits' + percentileComputation: + type: boolean + description: Whether to include this search when calculating processing-time percentiles. + default: true + x-categories: + - Advanced + attributeCriteriaComputedByMinProximity: + type: boolean + description: | + Whether the best matching attribute should be determined by minimum proximity. + + This setting only affects ranking if the Attribute ranking criterion comes before Proximity in the `ranking` setting. + If true, the best matching attribute is selected based on the minimum proximity of multiple matches. + Otherwise, the best matching attribute is determined by the order in the `searchableAttributes` setting. + default: false + x-categories: + - Advanced + enableABTest: + type: boolean + description: Whether to enable A/B testing for this search. + default: true + x-categories: + - Advanced + enableReRanking: + type: boolean + description: | + Whether this search will use [Dynamic Re-Ranking](https://www.algolia.com/doc/guides/algolia-ai/re-ranking/). + + This setting only has an effect if you activated Dynamic Re-Ranking for this index in the Algolia dashboard. + default: true + x-categories: + - Filtering diff --git a/specs/composition/common/schemas/SearchResponse.yml b/specs/composition/common/schemas/SearchResponse.yml new file mode 100644 index 0000000000..4040065084 --- /dev/null +++ b/specs/composition/common/schemas/SearchResponse.yml @@ -0,0 +1,35 @@ +searchResponse: + additionalProperties: true + allOf: + - $ref: '../../../common/schemas/SearchResponse.yml#/baseSearchResponse' + - $ref: '#/searchResults' + +searchResults: + type: object + additionalProperties: false + properties: + results: + type: array + description: Search results. + items: + $ref: '#/searchResultsItem' + +searchResultsItem: + allOf: + - $ref: '#/searchHits' + - $ref: '../../../common/schemas/SearchResponse.yml#/SearchPagination' + +searchHits: + type: object + additionalProperties: true + properties: + hits: + type: array + description: | + Search results (hits). + + Hits are records from your index that match the search criteria, augmented with additional attributes, such as, for highlighting. + items: + $ref: 'Hit.yml#/hit' + required: + - hits diff --git a/specs/composition/common/schemas/batchCompositionAction.yml b/specs/composition/common/schemas/batchCompositionAction.yml new file mode 100644 index 0000000000..5ee9a1a471 --- /dev/null +++ b/specs/composition/common/schemas/batchCompositionAction.yml @@ -0,0 +1,14 @@ +deleteCompositionAction: + type: object + description: Operation arguments when deleting. + additionalProperties: false + properties: + objectID: + $ref: '../../../common/parameters.yml#/objectID' + required: + - objectID + +batchCompositionAction: + oneOf: + - $ref: './listCompositionsResponse.yml#/composition' + - $ref: '#/deleteCompositionAction' diff --git a/specs/composition/common/schemas/compositionBehavior.yml b/specs/composition/common/schemas/compositionBehavior.yml new file mode 100644 index 0000000000..07e7fd9009 --- /dev/null +++ b/specs/composition/common/schemas/compositionBehavior.yml @@ -0,0 +1,88 @@ +compositionBehavior: + type: object + additionalProperties: false + properties: + injection: + title: injection + type: object + additionalProperties: false + properties: + main: + title: main + type: object + additionalProperties: false + properties: + source: + title: compositionSource + type: object + additionalProperties: false + properties: + search: + title: compositionSourceSearch + type: object + additionalProperties: false + properties: + index: + type: string + description: Composition Main Index name. + example: Products + params: + $ref: './SearchParams.yml#/mainInjectionQueryParameters' + required: + - index + required: + - search + required: + - source + insets: + type: array + description: list of insets of the current Composition. + minItems: 0 + maxItems: 2 + items: + $ref: '#/compositionInset' + required: + - main + required: + - injection + +compositionInset: + type: object + additionalProperties: false + properties: + name: + type: string + description: Inset name. + source: + title: compositionInsetSource + type: object + additionalProperties: false + properties: + search: + title: compositionInsetSourceSearch + type: object + additionalProperties: false + properties: + index: + type: string + description: Composition Main Index name. + example: Products + params: + $ref: './SearchParams.yml#/InsetsQueryParameters' + required: + - index + required: + - search + position: + type: integer + minimum: 0 + maximum: 19 + length: + type: integer + minimum: 0 + maximum: 20 + required: + - name + - source + - position + - length diff --git a/specs/composition/common/schemas/compositionRule.yml b/specs/composition/common/schemas/compositionRule.yml new file mode 100644 index 0000000000..66e38f7da1 --- /dev/null +++ b/specs/composition/common/schemas/compositionRule.yml @@ -0,0 +1,83 @@ +compositionRule: + type: object + additionalProperties: false + properties: + objectID: + $ref: '../../../common/parameters.yml#/objectID' + conditions: + type: array + minItems: 0 + maxItems: 25 + description: Conditions that trigger a composition rule. + items: + $ref: '#/condition' + consequence: + title: compositionRuleConsequence + type: object + description: Effect of the rule. + additionalProperties: false + properties: + behavior: + $ref: './compositionBehavior.yml#/compositionBehavior' + required: + - behavior + description: + type: string + description: Description of the rule's purpose to help you distinguish between different rules. + example: Display a promotional banner + enabled: + type: boolean + default: true + description: Whether the rule is active. + validity: + type: array + description: Time periods when the rule is active. + items: + $ref: '../../../common/schemas/Rule.yml#/timeRange' + required: + - objectID + - conditions + - consequence + +condition: + type: object + additionalProperties: false + properties: + pattern: + type: string + description: | + Query pattern that triggers the rule. + + You can use either a literal string, or a special pattern `{facet:ATTRIBUTE}`, where `ATTRIBUTE` is a facet name. + The rule is triggered if the query matches the literal string or a value of the specified facet. + For example, with `pattern: {facet:genre}`, the rule is triggered when users search for a genre, such as "comedy". + example: '{facet:genre}' + anchoring: + $ref: '#/anchoring' + alternatives: + type: boolean + description: Whether the pattern should match plurals, synonyms, and typos. + default: false + context: + $ref: '../../../common/schemas/Rule.yml#/context' + filters: + type: string + description: | + Filters that trigger the rule. + + You can add add filters using the syntax `facet:value` so that the rule is triggered, when the specific filter is selected. + You can use `filters` on its own or combine it with the `pattern` parameter. + example: 'genre:comedy' + +anchoring: + type: string + description: | + Which part of the search query the pattern should match: + + - `startsWith`. The pattern must match the beginning of the query. + - `endsWith`. The pattern must match the end of the query. + - `is`. The pattern must match the query exactly. + - `contains`. The pattern must match anywhere in the query. + + Empty queries are only allowed as patterns with `anchoring: is`. + enum: [is, startsWith, endsWith, contains] diff --git a/specs/composition/common/schemas/listCompositionsResponse.yml b/specs/composition/common/schemas/listCompositionsResponse.yml new file mode 100644 index 0000000000..1cb19638fc --- /dev/null +++ b/specs/composition/common/schemas/listCompositionsResponse.yml @@ -0,0 +1,32 @@ +listCompositionsResponse: + type: object + additionalProperties: false + properties: + items: + type: array + description: All compositions in your Algolia application. + items: + $ref: '#/composition' + nbPages: + type: integer + description: Number of pages. + example: 100 + required: + - items + - nbPages + +composition: + type: object + additionalProperties: false + properties: + objectID: + $ref: '../../../common/parameters.yml#/objectID' + description: + type: string + description: Composition name. + example: 'my lovely crafted composition' + behavior: + $ref: './compositionBehavior.yml#/compositionBehavior' + required: + - objectID + - behavior diff --git a/specs/composition/common/schemas/rulesBatchCompositionAction.yml b/specs/composition/common/schemas/rulesBatchCompositionAction.yml new file mode 100644 index 0000000000..b9c859b526 --- /dev/null +++ b/specs/composition/common/schemas/rulesBatchCompositionAction.yml @@ -0,0 +1,14 @@ +deleteCompositionRuleAction: + type: object + description: Operation arguments when deleting. + additionalProperties: false + properties: + objectID: + $ref: '../../../common/parameters.yml#/objectID' + required: + - objectID + +rulesBatchCompositionAction: + oneOf: + - $ref: './compositionRule.yml#/compositionRule' + - $ref: '#/deleteCompositionRuleAction' diff --git a/specs/composition/helpers/waitForCompositionTask.yml b/specs/composition/helpers/waitForCompositionTask.yml new file mode 100644 index 0000000000..b84d09ce51 --- /dev/null +++ b/specs/composition/helpers/waitForCompositionTask.yml @@ -0,0 +1,34 @@ +method: + get: + x-helper: true + tags: + - Records + operationId: waitForCompositionTask + summary: Wait for operation to complete + description: | + Wait for a task to complete to ensure synchronized composition updates. + + All Algolia write operations are asynchronous. When you make a request for a write operation, for example, to upsert or delete a composition, Algolia creates a task on a queue and returns a taskID. The task itself runs separately, depending on the server load. + parameters: + - in: query + name: compositionID + description: The ID of the composition on which the operation was performed. + required: true + schema: + type: string + - in: query + name: taskID + description: The taskID returned by the operation. + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '../common/schemas/GetTaskResponse.yml' + '400': + $ref: '../../common/responses/CompositionNotFound.yml' diff --git a/specs/composition/paths/advanced/getTask.yml b/specs/composition/paths/advanced/getTask.yml new file mode 100644 index 0000000000..5069d37f7e --- /dev/null +++ b/specs/composition/paths/advanced/getTask.yml @@ -0,0 +1,38 @@ +get: + tags: + - Compositions + operationId: getTask + x-acl: + - editSettings + - settings + - addObject + - deleteObject + - deleteIndex + description: | + Checks the status of a given task. + summary: Check task status + parameters: + - $ref: '../../common/parameters.yml#/compositionID' + - name: taskID + in: path + description: Unique task identifier. + required: true + schema: + type: integer + format: int64 + example: 1506303845001 + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '../../common/schemas/GetTaskResponse.yml' + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/IndexNotFound.yml' diff --git a/specs/composition/paths/manage_compositions/listCompositions.yml b/specs/composition/paths/manage_compositions/listCompositions.yml new file mode 100644 index 0000000000..5403c25c4d --- /dev/null +++ b/specs/composition/paths/manage_compositions/listCompositions.yml @@ -0,0 +1,28 @@ +get: + tags: + - Compositions + operationId: listCompositions + x-acl: + - editSettings + - settings + summary: List compositions + description: | + Lists all compositions in the current Algolia application. + parameters: + - $ref: '../../../common/parameters.yml#/Page' + - $ref: '../../../common/parameters.yml#/HitsPerPage' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '../../common/schemas/listCompositionsResponse.yml#/listCompositionsResponse' + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/CompositionNotFound.yml' diff --git a/specs/composition/paths/objects/multipleBatch.yml b/specs/composition/paths/objects/multipleBatch.yml new file mode 100644 index 0000000000..6ad1989a1d --- /dev/null +++ b/specs/composition/paths/objects/multipleBatch.yml @@ -0,0 +1,60 @@ +post: + tags: + - Compositions + operationId: multipleBatch + description: | + Adds, updates, or deletes compositions with a single API request. + x-acl: + - editSettings + summary: Batch action to multiple compositions + requestBody: + required: true + content: + application/json: + schema: + title: batchParams + description: Batch parameters. + type: object + additionalProperties: false + properties: + requests: + type: array + items: + title: multipleBatchRequest + type: object + additionalProperties: false + properties: + action: + $ref: '../../common/schemas/Batch.yml#/action' + body: + $ref: '../../common/schemas/batchCompositionAction.yml#/batchCompositionAction' + required: + - action + - body + required: + - requests + responses: + '200': + description: OK + content: + application/json: + schema: + title: multipleBatchResponse + type: object + additionalProperties: false + properties: + taskID: + type: object + description: Task IDs. One for each index. + additionalProperties: + $ref: '../../../common/responses/common.yml#/taskID' + required: + - taskID + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/IndexNotFound.yml' diff --git a/specs/composition/paths/objects/objects.yml b/specs/composition/paths/objects/objects.yml new file mode 100644 index 0000000000..5817adc75f --- /dev/null +++ b/specs/composition/paths/objects/objects.yml @@ -0,0 +1,27 @@ +get: + tags: + - Compositions + operationId: getComposition + x-acl: + - editSettings + - settings + summary: Retrieve a composition + description: | + Retrieve a single composition in the current Algolia application. + parameters: + - $ref: '../../common/parameters.yml#/compositionID' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '../../common/schemas/listCompositionsResponse.yml#/composition' + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/CompositionNotFound.yml' diff --git a/specs/composition/paths/rules/parameters.yml b/specs/composition/paths/rules/parameters.yml new file mode 100644 index 0000000000..ef2701465f --- /dev/null +++ b/specs/composition/paths/rules/parameters.yml @@ -0,0 +1,12 @@ +ObjectIDRule: + in: path + name: objectID + description: Unique identifier of a rule object. + required: true + schema: + $ref: '../../../common/parameters.yml#/ruleID' + +query: + type: string + description: Search query for rules. + default: '' diff --git a/specs/composition/paths/rules/rule.yml b/specs/composition/paths/rules/rule.yml new file mode 100644 index 0000000000..6b9721e32f --- /dev/null +++ b/specs/composition/paths/rules/rule.yml @@ -0,0 +1,29 @@ +get: + tags: + - Rules + operationId: getRule + x-acl: + - settings + summary: Retrieve a rule + description: | + Retrieves a rule by its ID. + To find the object ID of rules, use the [`search` operation](#tag/Rules/operation/searchRules). + + parameters: + - $ref: '../../common/parameters.yml#/compositionID' + - $ref: './parameters.yml#/ObjectIDRule' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '../../common/schemas/compositionRule.yml#/compositionRule' + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/IndexNotFound.yml' diff --git a/specs/composition/paths/rules/saveRules.yml b/specs/composition/paths/rules/saveRules.yml new file mode 100644 index 0000000000..409820f2d8 --- /dev/null +++ b/specs/composition/paths/rules/saveRules.yml @@ -0,0 +1,58 @@ +post: + tags: + - Rules + operationId: saveRules + x-acl: + - editSettings + summary: Create or update or delete composition rules + description: | + Create or update or delete multiple composition rules. + x-codegen-request-body-name: rules + parameters: + - $ref: '../../common/parameters.yml#/compositionID' + requestBody: + required: true + content: + application/json: + schema: + title: compositionRulesBatchParams + description: Composition rules batch parameters. + type: object + additionalProperties: false + properties: + requests: + type: array + items: + title: rulesMultipleBatchRequest + type: object + additionalProperties: false + properties: + action: + $ref: '../../common/schemas/Batch.yml#/action' + body: + $ref: '../../common/schemas/rulesBatchCompositionAction.yml#/rulesBatchCompositionAction' + required: + - action + - body + responses: + '200': + description: OK + content: + application/json: + schema: + title: rulesMultipleBatchResponse + type: object + additionalProperties: false + properties: + taskID: + $ref: '../../../common/responses/common.yml#/taskID' + required: + - taskID + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/IndexNotFound.yml' diff --git a/specs/composition/paths/rules/searchRules.yml b/specs/composition/paths/rules/searchRules.yml new file mode 100644 index 0000000000..accfa1b66b --- /dev/null +++ b/specs/composition/paths/rules/searchRules.yml @@ -0,0 +1,79 @@ +post: + tags: + - Rules + operationId: searchCompositionRules + x-use-read-transporter: true + x-cacheable: true + x-acl: + - settings + summary: Search for composition rules + description: Searches for composition rules in your index. + parameters: + - $ref: '../../common/parameters.yml#/compositionID' + requestBody: + content: + application/json: + schema: + title: searchCompositionRulesParams + type: object + description: Composition Rules search parameters. + additionalProperties: false + properties: + query: + $ref: './parameters.yml#/query' + anchoring: + $ref: '../../common/schemas/compositionRule.yml#/anchoring' + context: + type: string + description: Only return composition rules that match the context (exact match). + example: 'mobile' + page: + $ref: '../../../common/parameters.yml#/page' + hitsPerPage: + $ref: '../../../common/parameters.yml#/hitsPerPage' + enabled: + oneOf: + - type: boolean + description: | + If `true`, return only enabled composition rules. + If `false`, return only inactive composition rules. + By default, _all_ composition rules are returned. + - type: 'null' + default: null + responses: + '200': + description: OK + content: + application/json: + schema: + title: searchCompositionRulesResponse + type: object + additionalProperties: false + required: + - hits + - nbHits + - page + - nbPages + properties: + hits: + type: array + description: Composition rules that matched the search criteria. + items: + $ref: '../../common/schemas/compositionRule.yml#/compositionRule' + nbHits: + type: integer + description: Number of composition rules that matched the search criteria. + page: + type: integer + description: Current page. + nbPages: + type: integer + description: Number of pages. + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/IndexNotFound.yml' diff --git a/specs/composition/paths/search/run.yml b/specs/composition/paths/search/run.yml new file mode 100644 index 0000000000..e1aed1a40a --- /dev/null +++ b/specs/composition/paths/search/run.yml @@ -0,0 +1,32 @@ +post: + tags: + - Search + operationId: runSingleComposition + x-use-read-transporter: true + x-cacheable: true + x-acl: + - search + summary: Run a Composition + description: Runs a query on a single composition and returns matching results. + parameters: + - $ref: '../../common/parameters.yml#/compositionID' + requestBody: + content: + application/json: + schema: + $ref: '../../../common/schemas/SearchParams.yml#/searchParams' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '../../common/schemas/SearchResponse.yml#/searchResponse' + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/IndexNotFound.yml' diff --git a/specs/composition/paths/search/searchForFacetValues.yml b/specs/composition/paths/search/searchForFacetValues.yml new file mode 100644 index 0000000000..e7ade05927 --- /dev/null +++ b/specs/composition/paths/search/searchForFacetValues.yml @@ -0,0 +1,59 @@ +post: + tags: + - Search + operationId: searchForFacetValues + x-use-read-transporter: true + x-cacheable: true + x-acl: + - search + summary: Search for facet values + description: | + Searches for values of a specified facet attribute on the composition's main source's index. + + - By default, facet values are sorted by decreasing count. + You can adjust this with the `sortFacetValueBy` parameter. + - Searching for facet values doesn't work if you have **more than 65 searchable facets and searchable attributes combined**. + parameters: + - $ref: '../../common/parameters.yml#/compositionID' + - name: facetName + description: | + Facet attribute in which to search for values. + + This attribute must be included in the `attributesForFaceting` index setting with the `searchable()` modifier. + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + title: searchForFacetValuesRequest + type: object + additionalProperties: false + properties: + params: + title: searchForFacetValuesParams + type: object + properties: + query: + $ref: '../../../common/schemas/SearchParams.yml#/query' + maxFacetHits: + $ref: '../../../common/schemas/IndexSettings.yml#/maxFacetHits' + searchQuery: + $ref: '../../common/schemas/SearchParams.yml#/searchParams' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '../../common/schemas/SearchForFacetValuesResponse.yml#/searchForFacetValuesResponse' + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/IndexNotFound.yml' diff --git a/specs/composition/spec.yml b/specs/composition/spec.yml new file mode 100644 index 0000000000..eb9a6f6d4b --- /dev/null +++ b/specs/composition/spec.yml @@ -0,0 +1,101 @@ +openapi: 3.0.2 +info: + title: Composition API + description: Composition API. + version: 1.0.0 +components: + securitySchemes: + appId: + $ref: '../common/securitySchemes.yml#/appId' + apiKey: + $ref: '../common/securitySchemes.yml#/apiKey' +servers: + - url: https://{appId}.algolia.net + variables: + appId: + default: ALGOLIA_APPLICATION_ID + - url: https://{appId}-1.algolianet.com + variables: + appId: + default: ALGOLIA_APPLICATION_ID + - url: https://{appId}-2.algolianet.com + variables: + appId: + default: ALGOLIA_APPLICATION_ID + - url: https://{appId}-3.algolianet.com + variables: + appId: + default: ALGOLIA_APPLICATION_ID + - url: https://{appId}-dsn.algolia.net + variables: + appId: + default: ALGOLIA_APPLICATION_ID +security: + - appId: [] + apiKey: [] +tags: + - name: Compositions + description: | + Manage your compositions and composition settings. + - name: Rules + description: | + Manage your compositions rules. + - name: Search + description: Search one or more indices for matching records or facet values. +x-tagGroups: + - name: Search + tags: + - Compositions +paths: + # ###################### + # ### Custom request ### + # ###################### + /{path}: + $ref: '../common/paths/customRequest.yml' + + # ######################## + # ### Search Endpoints ### + # ######################## + /1/compositions/{compositionID}/run: + $ref: 'paths/search/run.yml' + /1/compositions/{compositionID}/facets/{facetName}/query: + $ref: 'paths/search/searchForFacetValues.yml' + + # ######################### + # ### Objects Endpoints ### + # ######################### + /1/compositions/{compositionID}: + $ref: 'paths/objects/objects.yml' + /1/compositions/*/batch: + $ref: 'paths/objects/multipleBatch.yml' + + # ####################### + # ### Rules Endpoints ### + # ####################### + /1/compositions/{compositionID}/rules/{objectID}: + $ref: 'paths/rules/rule.yml' + /1/compositions/{compositionID}/rules/batch: + $ref: 'paths/rules/saveRules.yml' + /1/compositions/{compositionID}/rules/search: + $ref: 'paths/rules/searchRules.yml' + + # ########################## + # ### Advanced Endpoints ### + # ########################## + /1/compositions/{compositionID}/task/{taskID}: + $ref: 'paths/advanced/getTask.yml' + + # ##################################### + # ### Manage Compositions Endpoints ### + # ##################################### + /1/compositions: + $ref: 'paths/manage_compositions/listCompositions.yml' + + # ############### + # ### Helpers ### + # ############### + /setClientApiKey: + $ref: '../common/helpers/setClientApiKey.yml#/method' + + /waitForCompositionTask: + $ref: 'helpers/waitForCompositionTask.yml#/method' diff --git a/templates/javascript/clients/api-single.mustache b/templates/javascript/clients/api-single.mustache index 2018f8dd74..3723fec808 100644 --- a/templates/javascript/clients/api-single.mustache +++ b/templates/javascript/clients/api-single.mustache @@ -91,6 +91,9 @@ export function create{{#lambda.titlecase}}{{clientName}}{{/lambda.titlecase}}({ {{#isSearchClient}} {{> client/api/helpers}} {{/isSearchClient}} + {{#isAlgoliaCompositionClient}} + {{> client/api/compositionHelpers}} + {{/isAlgoliaCompositionClient}} {{#operation}} {{> client/api/operation/jsdoc}} {{nickname}}{{#vendorExtensions.x-is-generic}}{{/vendorExtensions.x-is-generic}}( {{> client/api/operation/parameters}} ) : Promise<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}{{#vendorExtensions.x-is-generic}}{{/vendorExtensions.x-is-generic}}> { diff --git a/templates/javascript/clients/client/api/compositionHelpers.mustache b/templates/javascript/clients/client/api/compositionHelpers.mustache new file mode 100644 index 0000000000..41a4168750 --- /dev/null +++ b/templates/javascript/clients/client/api/compositionHelpers.mustache @@ -0,0 +1,35 @@ +/** + * Helper: Wait for a composition-level task to be published (completed) for a given `compositionID` and `taskID`. + * + * @summary Helper method that waits for a task to be published (completed). + * @param WaitForCompositionTaskOptions - The `WaitForCompositionTaskOptions` object. + * @param WaitForCompositionTaskOptions.compositionID - The `compositionID` where the operation was performed. + * @param WaitForCompositionTaskOptions.taskID - The `taskID` returned in the method response. + * @param WaitForCompositionTaskOptions.maxRetries - The maximum number of retries. 50 by default. + * @param WaitForCompositionTaskOptions.timeout - The function to decide how long to wait between retries. + * @param requestOptions - The requestOptions to send along with the query, they will be forwarded to the `getTask` method and merged with the transporter requestOptions. + */ +waitForCompositionTask( + { + compositionID, + taskID, + maxRetries = 50, + timeout = (retryCount: number): number => + Math.min(retryCount * 200, 5000), + }: WaitForCompositionTaskOptions, + requestOptions?: RequestOptions +): Promise { + let retryCount = 0; + + return createIterablePromise({ + func: () => this.getTask({ compositionID, taskID }, requestOptions), + validate: (response) => response.status === 'published', + aggregator: () => (retryCount += 1), + error: { + validate: () => retryCount >= maxRetries, + message: () => + `The maximum number of retries exceeded. (${retryCount}/${maxRetries})`, + }, + timeout: () => timeout(retryCount), + }); +}, diff --git a/templates/javascript/clients/client/api/imports.mustache b/templates/javascript/clients/client/api/imports.mustache index 2f223e5bff..429f45f6a5 100644 --- a/templates/javascript/clients/client/api/imports.mustache +++ b/templates/javascript/clients/client/api/imports.mustache @@ -9,6 +9,9 @@ import { serializeQueryParameters, createIterablePromise, {{/isSearchClient}} + {{#isAlgoliaCompositionClient}} + createIterablePromise, + {{/isAlgoliaCompositionClient}} } from '@algolia/client-common'; import type { CreateClientOptions, @@ -39,6 +42,9 @@ import type { WaitForAppTaskOptions, WaitForTaskOptions, {{/isSearchClient}} + {{#isAlgoliaCompositionClient}} + WaitForCompositionTaskOptions, + {{/isAlgoliaCompositionClient}} {{#operation}} {{#vendorExtensions}} {{#x-create-wrapping-object}} diff --git a/templates/javascript/clients/client/model/clientMethodProps.mustache b/templates/javascript/clients/client/model/clientMethodProps.mustache index 3e454a837e..d258335492 100644 --- a/templates/javascript/clients/client/model/clientMethodProps.mustache +++ b/templates/javascript/clients/client/model/clientMethodProps.mustache @@ -184,5 +184,28 @@ export type ReplaceAllObjectsOptions = { } {{/isAlgoliasearchClient}} {{/isSearchClient}} +{{#isAlgoliaCompositionClient}} +export type WaitForCompositionTaskOptions = { + /** + * The maximum number of retries. 50 by default. + */ + maxRetries?: number; + + /** + * The function to decide how long to wait between retries. + */ + timeout?: (retryCount: number) => number; + + /** + * The `taskID` returned by the method response. + */ + + taskID: number; + /** + * The `compositionID` where the operation was performed. + */ + compositionID: string; +}; +{{/isAlgoliaCompositionClient}} {{/apiInfo.apis.0}} \ No newline at end of file diff --git a/templates/javascript/snippets/init.mustache b/templates/javascript/snippets/init.mustache index d8b2819023..ed3c1a63ac 100644 --- a/templates/javascript/snippets/init.mustache +++ b/templates/javascript/snippets/init.mustache @@ -1 +1 @@ -const client = {{{clientName}}}("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY"){{^isSearchClient}}.{{{initMethod}}}({{#hasRegionalHost}} {region: '{{defaultRegion}}'} {{/hasRegionalHost}}){{/isSearchClient}}; \ No newline at end of file +const client = {{{clientName}}}("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY"){{^isSearchClient}}{{^isCompositionClient}}.{{{initMethod}}}({{#hasRegionalHost}} {region: '{{defaultRegion}}'} {{/hasRegionalHost}}){{/isCompositionClient}}{{/isSearchClient}}; \ No newline at end of file diff --git a/templates/javascript/tests/client/client.mustache b/templates/javascript/tests/client/client.mustache index fcefd2ecc8..47c559c017 100644 --- a/templates/javascript/tests/client/client.mustache +++ b/templates/javascript/tests/client/client.mustache @@ -2,7 +2,12 @@ /* eslint-disable eslint/no-unused-vars */ import { describe, test, expect } from 'vitest'; +{{^isCompositionClient}} import { {{{clientName}}} } from '{{{importPackage}}}'; +{{/isCompositionClient}} +{{#isCompositionClient}} +import { compositionClient } from '@algolia/client-composition'; +{{/isCompositionClient}} import { nodeEchoRequester } from '@algolia/requester-testing'; import type { EchoResponse } from '@algolia/requester-testing'; @@ -10,7 +15,7 @@ const appId = 'test-app-id'; const apiKey = 'test-api-key'; function createClient() { - return {{{clientName}}}(appId, apiKey{{#isSearchClient}}, { requester: nodeEchoRequester() }{{/isSearchClient}}){{^isSearchClient}}.{{{initMethod}}}({ options: { requester: nodeEchoRequester() }, {{#hasRegionalHost}} region:'{{{defaultRegion}}}' {{/hasRegionalHost}} });{{/isSearchClient}}; + return {{^isCompositionClient}}{{{clientName}}}{{/isCompositionClient}}{{#isCompositionClient}}compositionClient{{/isCompositionClient}}(appId, apiKey{{#isStandaloneClient}}, { requester: nodeEchoRequester() }{{/isStandaloneClient}}){{^isStandaloneClient}}.{{{initMethod}}}({ options: { requester: nodeEchoRequester() }, {{#hasRegionalHost}} region:'{{{defaultRegion}}}' {{/hasRegionalHost}} });{{/isStandaloneClient}}; } {{#blocksClient}} @@ -19,8 +24,8 @@ function createClient() { describe('init', () => { test('sets authMode', async () => { - const qpClient = {{{clientName}}}('foo', 'bar'{{#isSearchClient}}, { requester: nodeEchoRequester(), authMode: 'WithinQueryParameters' }{{/isSearchClient}}){{^isSearchClient}}.{{{initMethod}}}({ options: { requester: nodeEchoRequester(), authMode: 'WithinQueryParameters' }, {{#hasRegionalHost}} region:'{{{defaultRegion}}}' {{/hasRegionalHost}} });{{/isSearchClient}}; - const headerClient = {{{clientName}}}('foo', 'bar'{{#isSearchClient}}, { requester: nodeEchoRequester(), authMode: 'WithinHeaders' }{{/isSearchClient}}){{^isSearchClient}}.{{{initMethod}}}({ options: { requester: nodeEchoRequester(), authMode: 'WithinHeaders' }, {{#hasRegionalHost}} region:'{{{defaultRegion}}}' {{/hasRegionalHost}} });{{/isSearchClient}}; + const qpClient = {{^isCompositionClient}}{{{clientName}}}{{/isCompositionClient}}{{#isCompositionClient}}compositionClient{{/isCompositionClient}}('foo', 'bar'{{#isStandaloneClient}}, { requester: nodeEchoRequester(), authMode: 'WithinQueryParameters' }{{/isStandaloneClient}}){{^isStandaloneClient}}.{{{initMethod}}}({ options: { requester: nodeEchoRequester(), authMode: 'WithinQueryParameters' }, {{#hasRegionalHost}} region:'{{{defaultRegion}}}' {{/hasRegionalHost}} });{{/isStandaloneClient}}; + const headerClient = {{^isCompositionClient}}{{{clientName}}}{{/isCompositionClient}}{{#isCompositionClient}}compositionClient{{/isCompositionClient}}('foo', 'bar'{{#isStandaloneClient}}, { requester: nodeEchoRequester(), authMode: 'WithinHeaders' }{{/isStandaloneClient}}){{^isStandaloneClient}}.{{{initMethod}}}({ options: { requester: nodeEchoRequester(), authMode: 'WithinHeaders' }, {{#hasRegionalHost}} region:'{{{defaultRegion}}}' {{/hasRegionalHost}} });{{/isStandaloneClient}}; const qpResult = (await qpClient.customGet({ path: '1/foo', diff --git a/templates/javascript/tests/client/createClient.mustache b/templates/javascript/tests/client/createClient.mustache index 3dc141151d..1bbb0eca9b 100644 --- a/templates/javascript/tests/client/createClient.mustache +++ b/templates/javascript/tests/client/createClient.mustache @@ -1,7 +1,7 @@ -{{^autoCreateClient}}const client = {{/autoCreateClient}}{{{clientName}}}( +{{^autoCreateClient}}const client = {{/autoCreateClient}}{{^isCompositionClient}}{{{clientName}}}{{/isCompositionClient}}{{#isCompositionClient}}compositionClient{{/isCompositionClient}}( '{{parametersWithDataTypeMap.appId.value}}', '{{parametersWithDataTypeMap.apiKey.value}}' - {{#isSearchClient}}, + {{#isStandaloneClient}}, { {{#useEchoRequester}} requester: nodeEchoRequester(), @@ -19,8 +19,8 @@ ] {{/hasCustomHosts}} } - {{/isSearchClient}} -){{^isSearchClient}}.{{{initMethod}}}( + {{/isStandaloneClient}} +){{^isStandaloneClient}}.{{{initMethod}}}( { options: { {{#useEchoRequester}} @@ -44,4 +44,4 @@ region: '{{{parametersWithDataTypeMap.region.value}}}' {{/hasRegionalHost}} }) -{{/isSearchClient}}; \ No newline at end of file +{{/isStandaloneClient}}; \ No newline at end of file diff --git a/templates/javascript/tests/e2e/e2e.mustache b/templates/javascript/tests/e2e/e2e.mustache index 64fc2db86b..079424f392 100644 --- a/templates/javascript/tests/e2e/e2e.mustache +++ b/templates/javascript/tests/e2e/e2e.mustache @@ -6,7 +6,12 @@ import { union } from '../helpers.js'; import * as dotenv from 'dotenv'; dotenv.config({path:'../../.env'}); +{{^isCompositionClient}} import { {{{clientName}}} } from '{{{importPackage}}}'; +{{/isCompositionClient}} +{{#isCompositionClient}} +import { compositionClient } from '@algolia/client-composition'; +{{/isCompositionClient}} import type { RequestOptions } from '@algolia/client-common'; if (!process.env.ALGOLIA_APPLICATION_ID) { @@ -17,7 +22,7 @@ if (!process.env.{{e2eApiKey}}) { throw new Error("please provide an `{{e2eApiKey}}` env var for e2e tests"); } -const client = {{{clientName}}}(process.env.ALGOLIA_APPLICATION_ID, process.env.{{e2eApiKey}}){{^isSearchClient}}.{{{initMethod}}}({{#hasRegionalHost}} {region:'{{{defaultRegion}}}'} {{/hasRegionalHost}}){{/isSearchClient}}; +const client = {{^isCompositionClient}}{{{clientName}}}{{/isCompositionClient}}{{#isCompositionClient}}compositionClient{{/isCompositionClient}}(process.env.ALGOLIA_APPLICATION_ID, process.env.{{e2eApiKey}}){{^isStandaloneClient}}.{{{initMethod}}}({{#hasRegionalHost}} {region:'{{{defaultRegion}}}'} {{/hasRegionalHost}}){{/isStandaloneClient}}; {{#blocksE2E}} describe('{{operationId}}', () => { diff --git a/templates/javascript/tests/package.mustache b/templates/javascript/tests/package.mustache index c0b58b0077..fe7c02f9e5 100644 --- a/templates/javascript/tests/package.mustache +++ b/templates/javascript/tests/package.mustache @@ -7,6 +7,7 @@ }, "dependencies": { "algoliasearch": "link:../../../clients/algoliasearch-client-javascript/packages/algoliasearch", + "@algolia/client-composition": "link:../../../clients/algoliasearch-client-javascript/packages/client-composition", "@algolia/requester-testing": "link:../../../clients/algoliasearch-client-javascript/packages/requester-testing" }, "devDependencies": { diff --git a/templates/javascript/tests/requests/requests.mustache b/templates/javascript/tests/requests/requests.mustache index 4b77e28037..96de0298f5 100644 --- a/templates/javascript/tests/requests/requests.mustache +++ b/templates/javascript/tests/requests/requests.mustache @@ -1,7 +1,12 @@ // {{generationBanner}} import { describe, test, expect } from 'vitest'; +{{^isCompositionClient}} import { {{{clientName}}} } from '{{{importPackage}}}'; +{{/isCompositionClient}} +{{#isCompositionClient}} +import { compositionClient } from '@algolia/client-composition'; +{{/isCompositionClient}} import { nodeEchoRequester } from '@algolia/requester-testing'; import type { EchoResponse } from '@algolia/requester-testing'; import type { ClientOptions } from '@algolia/client-common'; @@ -10,7 +15,7 @@ const appId = process.env.ALGOLIA_APPLICATION_ID || 'test_app_id'; const apiKey = process.env.ALGOLIA_SEARCH_KEY || 'test_api_key'; const clientOptions: ClientOptions = { requester: nodeEchoRequester() }; // this makes sure the types are correctly exported -const client = {{{clientName}}}(appId, apiKey{{#isSearchClient}}, { requester: nodeEchoRequester() }{{/isSearchClient}}){{^isSearchClient}}.{{{initMethod}}}({ options: clientOptions, {{#hasRegionalHost}} region:'{{{defaultRegion}}}' {{/hasRegionalHost}} });{{/isSearchClient}}; +const client = {{^isCompositionClient}}{{{clientName}}}{{/isCompositionClient}}{{#isCompositionClient}}compositionClient{{/isCompositionClient}}(appId, apiKey{{#isStandaloneClient}}, { requester: nodeEchoRequester() }{{/isStandaloneClient}}){{^isStandaloneClient}}.{{{initMethod}}}({ options: clientOptions, {{#hasRegionalHost}} region:'{{{defaultRegion}}}' {{/hasRegionalHost}} });{{/isStandaloneClient}}; {{#blocksRequests}} describe('{{operationId}}', () => { diff --git a/tests/CTS/client/composition/api.json b/tests/CTS/client/composition/api.json new file mode 100644 index 0000000000..71170ea471 --- /dev/null +++ b/tests/CTS/client/composition/api.json @@ -0,0 +1,89 @@ +[ + { + "testName": "calls api with correct read host", + "autoCreateClient": false, + "steps": [ + { + "type": "createClient", + "parameters": { + "appId": "test-app-id", + "apiKey": "test-api-key" + } + }, + { + "type": "method", + "method": "customGet", + "parameters": { + "path": "test" + }, + "expected": { + "type": "host", + "match": "test-app-id-dsn.algolia.net" + } + } + ] + }, + { + "testName": "calls api with correct write host", + "autoCreateClient": false, + "steps": [ + { + "type": "createClient", + "parameters": { + "appId": "test-app-id", + "apiKey": "test-api-key" + } + }, + { + "type": "method", + "method": "customPost", + "parameters": { + "path": "test" + }, + "expected": { + "type": "host", + "match": "test-app-id.algolia.net" + } + } + ] + }, + { + "testName": "test the compression strategy", + "autoCreateClient": false, + "steps": [ + { + "type": "createClient", + "parameters": { + "appId": "test-app-id", + "apiKey": "test-api-key", + "customHosts": [ + { + "port": 6678 + } + ], + "gzip": true + } + }, + { + "type": "method", + "method": "customPost", + "parameters": { + "path": "1/test/gzip", + "parameters": {}, + "body": { + "message": "this is a compressed body" + } + }, + "expected": { + "type": "response", + "match": { + "message": "ok compression test server response", + "body": { + "message": "this is a compressed body" + } + } + } + } + ] + } +] diff --git a/tests/CTS/requests/composition/getComposition.json b/tests/CTS/requests/composition/getComposition.json new file mode 100644 index 0000000000..849e3100d7 --- /dev/null +++ b/tests/CTS/requests/composition/getComposition.json @@ -0,0 +1,11 @@ +[ + { + "parameters": { + "compositionID": "foo" + }, + "request": { + "path": "/1/compositions/foo", + "method": "GET" + } + } +] diff --git a/tests/CTS/requests/composition/getRule.json b/tests/CTS/requests/composition/getRule.json new file mode 100644 index 0000000000..3a91a7bd6d --- /dev/null +++ b/tests/CTS/requests/composition/getRule.json @@ -0,0 +1,12 @@ +[ + { + "parameters": { + "compositionID": "foo", + "objectID": "123" + }, + "request": { + "path": "/1/compositions/foo/rules/123", + "method": "GET" + } + } +] diff --git a/tests/CTS/requests/composition/getTask.json b/tests/CTS/requests/composition/getTask.json new file mode 100644 index 0000000000..d86810bc1d --- /dev/null +++ b/tests/CTS/requests/composition/getTask.json @@ -0,0 +1,12 @@ +[ + { + "parameters": { + "compositionID": "foo", + "taskID": 42 + }, + "request": { + "path": "/1/compositions/foo/task/42", + "method": "GET" + } + } +] diff --git a/tests/CTS/requests/composition/listCompositions.json b/tests/CTS/requests/composition/listCompositions.json new file mode 100644 index 0000000000..aeddc5c455 --- /dev/null +++ b/tests/CTS/requests/composition/listCompositions.json @@ -0,0 +1,16 @@ +[ + { + "parameters": {}, + "request": { + "path": "/1/compositions", + "method": "GET" + } + }, + { + "parameters": {}, + "request": { + "path": "/1/compositions", + "method": "GET" + } + } +] diff --git a/tests/CTS/requests/composition/multipleBatch.json b/tests/CTS/requests/composition/multipleBatch.json new file mode 100644 index 0000000000..aa468e3712 --- /dev/null +++ b/tests/CTS/requests/composition/multipleBatch.json @@ -0,0 +1,64 @@ +[ + { + "parameters": { + "requests": [ + { + "action": "upsert", + "body": { + "objectID": "foo", + "behavior": { + "injection": { + "main": { + "source": { + "search": { + "index": "bar" + } + } + }, + "insets": [] + } + } + } + }, + { + "action": "delete", + "body": { + "objectID": "baz" + } + } + ] + }, + "request": { + "path": "/1/compositions/*/batch", + "method": "POST", + "body": { + "requests": [ + { + "action": "upsert", + "body": { + "behavior": { + "injection": { + "insets": [], + "main": { + "source": { + "search": { + "index": "bar" + } + } + } + } + }, + "objectID": "foo" + } + }, + { + "action": "delete", + "body": { + "objectID": "baz" + } + } + ] + } + } + } +] diff --git a/tests/CTS/requests/composition/runSingleComposition.json b/tests/CTS/requests/composition/runSingleComposition.json new file mode 100644 index 0000000000..7d35bfb327 --- /dev/null +++ b/tests/CTS/requests/composition/runSingleComposition.json @@ -0,0 +1,17 @@ +[ + { + "parameters": { + "compositionID": "foo", + "searchParams": { + "query": "batman" + } + }, + "request": { + "path": "/1/compositions/foo/run", + "method": "POST", + "body": { + "query": "batman" + } + } + } +] diff --git a/tests/CTS/requests/composition/saveRules.json b/tests/CTS/requests/composition/saveRules.json new file mode 100644 index 0000000000..1cafbabd0e --- /dev/null +++ b/tests/CTS/requests/composition/saveRules.json @@ -0,0 +1,67 @@ +[ + { + "parameters": { + "compositionID": "foo", + "rules": { + "requests": [ + { + "action": "upsert", + "body": { + "objectID": "123", + "conditions": [ + { + "pattern": "a" + } + ], + "consequence": { + "behavior": { + "injection": { + "main": { + "source": { + "search": { + "index": "" + } + } + } + } + } + } + } + } + ] + } + }, + "request": { + "path": "/1/compositions/foo/rules/batch", + "method": "POST", + "body": { + "requests": [ + { + "action": "upsert", + "body": { + "objectID": "123", + "conditions": [ + { + "pattern": "a" + } + ], + "consequence": { + "behavior": { + "injection": { + "main": { + "source": { + "search": { + "index": "" + } + } + } + } + } + } + } + } + ] + } + } + } +] diff --git a/tests/CTS/requests/composition/searchCompositionRules.json b/tests/CTS/requests/composition/searchCompositionRules.json new file mode 100644 index 0000000000..5ed13620bb --- /dev/null +++ b/tests/CTS/requests/composition/searchCompositionRules.json @@ -0,0 +1,17 @@ +[ + { + "parameters": { + "compositionID": "foo", + "searchCompositionRulesParams": { + "query": "batman" + } + }, + "request": { + "path": "/1/compositions/foo/rules/search", + "method": "POST", + "body": { + "query": "batman" + } + } + } +] diff --git a/tests/CTS/requests/composition/searchForFacetValues.json b/tests/CTS/requests/composition/searchForFacetValues.json new file mode 100644 index 0000000000..a94217c83a --- /dev/null +++ b/tests/CTS/requests/composition/searchForFacetValues.json @@ -0,0 +1,22 @@ +[ + { + "parameters": { + "compositionID": "foo", + "facetName": "brand", + "searchForFacetValuesRequest": { + "params": { + "maxFacetHits": 10 + } + } + }, + "request": { + "path": "/1/compositions/foo/facets/brand/query", + "method": "POST", + "body": { + "params": { + "maxFacetHits": 10 + } + } + } + } +] diff --git a/tests/output/javascript/yarn.lock b/tests/output/javascript/yarn.lock index 057a0bee1b..0c74a9e063 100644 --- a/tests/output/javascript/yarn.lock +++ b/tests/output/javascript/yarn.lock @@ -5,6 +5,12 @@ __metadata: version: 8 cacheKey: 10 +"@algolia/client-composition@link:../../../clients/algoliasearch-client-javascript/packages/client-composition::locator=javascript-tests%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@algolia/client-composition@link:../../../clients/algoliasearch-client-javascript/packages/client-composition::locator=javascript-tests%40workspace%3A." + languageName: node + linkType: soft + "@algolia/requester-testing@link:../../../clients/algoliasearch-client-javascript/packages/requester-testing::locator=javascript-tests%40workspace%3A.": version: 0.0.0-use.local resolution: "@algolia/requester-testing@link:../../../clients/algoliasearch-client-javascript/packages/requester-testing::locator=javascript-tests%40workspace%3A." @@ -341,12 +347,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:22.7.7": - version: 22.7.7 - resolution: "@types/node@npm:22.7.7" +"@types/node@npm:22.8.1": + version: 22.8.1 + resolution: "@types/node@npm:22.8.1" dependencies: - undici-types: "npm:~6.19.2" - checksum: 10/ada6c5f850fa09621e21923d7b17c3f3b5264c3b39c0953006f4a8b0b3d4b6d77ac02e2bbf8bae1d493abf81668804624470d895dd4483875fde8382b6eb7933 + undici-types: "npm:~6.19.8" + checksum: 10/ae969e3d956dead1422c35d568ea5d48dd124a38a1a337cbd120fec6e13cc92b45c7308f91f1139fcd2337a67d4704d5614d6a2c444b1fb268f85e9f1d24c713 languageName: node linkType: hard @@ -946,8 +952,9 @@ __metadata: version: 0.0.0-use.local resolution: "javascript-tests@workspace:." dependencies: + "@algolia/client-composition": "link:../../../clients/algoliasearch-client-javascript/packages/client-composition" "@algolia/requester-testing": "link:../../../clients/algoliasearch-client-javascript/packages/requester-testing" - "@types/node": "npm:22.7.7" + "@types/node": "npm:22.8.1" algoliasearch: "link:../../../clients/algoliasearch-client-javascript/packages/algoliasearch" dotenv: "npm:16.4.5" typescript: "npm:5.6.3" @@ -1525,15 +1532,15 @@ __metadata: "typescript@patch:typescript@npm%3A5.6.3#optional!builtin": version: 5.6.3 - resolution: "typescript@patch:typescript@npm%3A5.6.3#optional!builtin::version=5.6.3&hash=b45daf" + resolution: "typescript@patch:typescript@npm%3A5.6.3#optional!builtin::version=5.6.3&hash=8c6c40" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10/dc4bec403cd33a204b655b1152a096a08e7bad2c931cb59ef8ff26b6f2aa541bf98f09fc157958a60c921b1983a8dde9a85b692f9de60fa8f574fd131e3ae4dd + checksum: 10/00504c01ee42d470c23495426af07512e25e6546bce7e24572e72a9ca2e6b2e9bea63de4286c3cfea644874da1467dcfca23f4f98f7caf20f8b03c0213bb6837 languageName: node linkType: hard -"undici-types@npm:~6.19.2": +"undici-types@npm:~6.19.8": version: 6.19.8 resolution: "undici-types@npm:6.19.8" checksum: 10/cf0b48ed4fc99baf56584afa91aaffa5010c268b8842f62e02f752df209e3dea138b372a60a963b3b2576ed932f32329ce7ddb9cb5f27a6c83040d8cd74b7a70