Skip to content

Commit 6b50ef0

Browse files
authored
feat(javascript): add abtesting client, better init usage (#784)
1 parent 5d4926f commit 6b50ef0

File tree

14 files changed

+238
-89
lines changed

14 files changed

+238
-89
lines changed

clients/algoliasearch-client-javascript/bundlesize.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"files": [
33
{
44
"path": "packages/algoliasearch/dist/algoliasearch.umd.js",
5-
"maxSize": "7.85KB"
5+
"maxSize": "8.40KB"
66
},
77
{
88
"path": "packages/algoliasearch/dist/lite/lite.umd.js",

clients/algoliasearch-client-javascript/packages/algoliasearch/__tests__/algoliasearch.test.ts

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,100 @@ describe('api', () => {
3939
expect(client.search).not.toBeUndefined();
4040
});
4141

42-
it('provides an init method for the analytics client', () => {
43-
expect(client.initAnalytics).not.toBeUndefined();
44-
});
42+
describe('init clients', () => {
43+
it('provides an init method for the analytics client', () => {
44+
expect(client.initAnalytics).not.toBeUndefined();
45+
});
4546

46-
it('provides an init method for the personalization client', () => {
47-
expect(client.initPersonalization).not.toBeUndefined();
47+
it('provides an init method for the abtesting client', () => {
48+
expect(client.initAbtesting).not.toBeUndefined();
49+
});
50+
51+
it('provides an init method for the personalization client', () => {
52+
expect(client.initPersonalization).not.toBeUndefined();
53+
});
54+
55+
it('default `init` clients to the root `algoliasearch` credentials', async () => {
56+
const abtestingClient = client.initAbtesting();
57+
const analyticsClient = client.initAnalytics();
58+
const personalizationClient = client.initPersonalization({
59+
region: 'eu',
60+
});
61+
62+
const res1 = (await abtestingClient.get({
63+
path: 'abtestingClient',
64+
})) as unknown as EchoResponse;
65+
const res2 = (await analyticsClient.get({
66+
path: 'analyticsClient',
67+
})) as unknown as EchoResponse;
68+
const res3 = (await personalizationClient.get({
69+
path: 'personalizationClient',
70+
})) as unknown as EchoResponse;
71+
72+
expect(res1.headers).toEqual(
73+
expect.objectContaining({
74+
'x-algolia-application-id': 'APP_ID',
75+
'x-algolia-api-key': 'API_KEY',
76+
})
77+
);
78+
expect(res2.headers).toEqual(
79+
expect.objectContaining({
80+
'x-algolia-application-id': 'APP_ID',
81+
'x-algolia-api-key': 'API_KEY',
82+
})
83+
);
84+
expect(res3.headers).toEqual(
85+
expect.objectContaining({
86+
'x-algolia-application-id': 'APP_ID',
87+
'x-algolia-api-key': 'API_KEY',
88+
})
89+
);
90+
});
91+
92+
it('`init` clients accept different credentials', async () => {
93+
const abtestingClient = client.initAbtesting({
94+
appId: 'appId1',
95+
apiKey: 'apiKey1',
96+
});
97+
const analyticsClient = client.initAnalytics({
98+
appId: 'appId2',
99+
apiKey: 'apiKey2',
100+
});
101+
const personalizationClient = client.initPersonalization({
102+
appId: 'appId3',
103+
apiKey: 'apiKey3',
104+
region: 'eu',
105+
});
106+
107+
const res1 = (await abtestingClient.get({
108+
path: 'abtestingClient',
109+
})) as unknown as EchoResponse;
110+
const res2 = (await analyticsClient.get({
111+
path: 'analyticsClient',
112+
})) as unknown as EchoResponse;
113+
const res3 = (await personalizationClient.get({
114+
path: 'personalizationClient',
115+
})) as unknown as EchoResponse;
116+
117+
expect(res1.headers).toEqual(
118+
expect.objectContaining({
119+
'x-algolia-application-id': 'appId1',
120+
'x-algolia-api-key': 'apiKey1',
121+
})
122+
);
123+
expect(res2.headers).toEqual(
124+
expect.objectContaining({
125+
'x-algolia-application-id': 'appId2',
126+
'x-algolia-api-key': 'apiKey2',
127+
})
128+
);
129+
expect(res3.headers).toEqual(
130+
expect.objectContaining({
131+
'x-algolia-application-id': 'appId3',
132+
'x-algolia-api-key': 'apiKey3',
133+
})
134+
);
135+
});
48136
});
49137
});
50138

clients/algoliasearch-client-javascript/yarn.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1330,7 +1330,7 @@ __metadata:
13301330
languageName: unknown
13311331
linkType: soft
13321332

1333-
"@experimental-api-clients-automation/client-abtesting@workspace:packages/client-abtesting":
1333+
"@experimental-api-clients-automation/client-abtesting@0.7.2, @experimental-api-clients-automation/client-abtesting@workspace:packages/client-abtesting":
13341334
version: 0.0.0-use.local
13351335
resolution: "@experimental-api-clients-automation/client-abtesting@workspace:packages/client-abtesting"
13361336
dependencies:

generators/src/main/java/com/algolia/codegen/AlgoliaJavaScriptGenerator.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ private void setDefaultGeneratorOptions() {
117117
if (isAlgoliasearchClient) {
118118
// Files used to create the package.json of the algoliasearch package
119119
additionalProperties.put("analyticsVersion", Utils.getOpenApiToolsField("javascript", "analytics", "packageVersion"));
120+
additionalProperties.put("abtestingVersion", Utils.getOpenApiToolsField("javascript", "abtesting", "packageVersion"));
120121
additionalProperties.put("personalizationVersion", Utils.getOpenApiToolsField("javascript", "personalization", "packageVersion"));
121122
additionalProperties.put("searchVersion", Utils.getOpenApiToolsField("javascript", "search", "packageVersion"));
122123

playground/javascript/node/algoliasearch.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,8 @@ const apiKey = process.env.ALGOLIA_SEARCH_KEY || '**** SEARCH_API_KEY *****';
1212

1313
const searchIndex = process.env.SEARCH_INDEX || 'test_index';
1414
const searchQuery = process.env.SEARCH_QUERY || 'test_query';
15-
16-
const analyticsAppId =
17-
process.env.ALGOLIA_APPLICATION_ID || '**** APP_ID *****';
18-
const analyticsApiKey =
19-
process.env.ALGOLIA_ANALYTICS_KEY || '**** ANALYTICS_API_KEY *****';
20-
2115
const analyticsIndex = process.env.ANALYTICS_INDEX || 'test_index';
2216

23-
const personalizationAppId =
24-
process.env.ALGOLIA_APPLICATION_ID || '**** APP_ID *****';
25-
const personalizationApiKey =
26-
process.env.ALGOLIA_RECOMMENDATION_KEY || '**** RECOMMENDATION_API_KEY *****';
27-
2817
// Init client with appId and apiKey
2918
const client = algoliasearch(appId, apiKey);
3019
const clientLite = liteClient(appId, apiKey);
@@ -89,17 +78,14 @@ async function testAlgoliasearch() {
8978
}
9079

9180
try {
92-
const analyticsClient = client.initAnalytics(
93-
analyticsAppId,
94-
analyticsApiKey
95-
);
81+
const analyticsClient = client.initAnalytics();
9682

9783
const res = await analyticsClient.getTopFilterForAttribute({
9884
attribute: 'myAttribute1,myAttribute2',
9985
index: analyticsIndex,
10086
});
10187

102-
console.log(`[OK analytics ]`, res);
88+
console.log(`[OK analytics]`, res);
10389
} catch (e) {
10490
if (e instanceof ApiError) {
10591
return console.log(`[${e.status}] ${e.message}`, e.stackTrace);
@@ -109,13 +95,27 @@ async function testAlgoliasearch() {
10995
}
11096

11197
try {
112-
const personalizationCilent = client.initPersonalization(
113-
personalizationAppId,
114-
personalizationApiKey,
115-
'eu'
116-
);
98+
const abtestingClient = client.initAbtesting();
99+
100+
const res = await abtestingClient.getABTest({
101+
id: 42,
102+
});
103+
104+
console.log(`[OK abtesting]`, res);
105+
} catch (e) {
106+
if (e instanceof ApiError) {
107+
return console.log(`[${e.status}] ${e.message}`, e.stackTrace);
108+
}
109+
110+
console.log('[ERROR abtesting]', e);
111+
}
112+
113+
try {
114+
const personalizationClient = client.initPersonalization({
115+
region: 'eu',
116+
});
117117

118-
const res = await personalizationCilent.getUserTokenProfile({
118+
const res = await personalizationClient.getUserTokenProfile({
119119
userToken: 'wouhou',
120120
});
121121

playground/javascript/node/search.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { searchClient } from '@experimental-api-clients-automation/client-search';
22
import { ApiError } from '@experimental-api-clients-automation/client-common';
33
import dotenv from 'dotenv';
4+
import { echoRequester } from '@experimental-api-clients-automation/requester-node-http';
45

56
dotenv.config({ path: '../../.env' });
67

templates/javascript/clients/algoliasearch/builds/browser.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { createXhrRequester } from '{{{npmNamespace}}}/requester-browser-xhr';
1515
export function algoliasearch(
1616
appId: string,
1717
apiKey: string,
18-
options?: { requester?: Requester; hosts?: Host[] }
18+
options?: CommonClientOptions
1919
) {
2020
{{> algoliasearch/builds/checkParameters}}
2121

templates/javascript/clients/algoliasearch/builds/imports.mustache

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
1-
import type {
2-
AnalyticsClient,
3-
Region as AnalyticsRegion,
4-
} from '{{{npmNamespace}}}/client-analytics/src/analyticsClient';
5-
import { createAnalyticsClient } from '{{{npmNamespace}}}/client-analytics/src/analyticsClient';
6-
import type {
7-
PersonalizationClient,
8-
Region as PersonalizationRegion,
9-
} from '{{{npmNamespace}}}/client-personalization/src/personalizationClient';
10-
import { createPersonalizationClient } from '{{{npmNamespace}}}/client-personalization/src/personalizationClient';
11-
import {
12-
createSearchClient,
13-
apiClientVersion as searchClientVersion,
14-
} from '{{{npmNamespace}}}/client-search/src/searchClient';
15-
import type {
16-
CreateClientOptions,
17-
Host,
18-
Requester,
19-
} from '{{{npmNamespace}}}/client-common';
1+
import type { Region as AnalyticsRegion, AnalyticsClient } from '{{{npmNamespace}}}/client-analytics/src/analyticsClient';
2+
import { createAnalyticsClient, REGIONS as analyticsRegions } from '{{{npmNamespace}}}/client-analytics/src/analyticsClient';
3+
4+
import type { Region as AbtestingRegion, AbtestingClient } from '{{{npmNamespace}}}/client-abtesting/src/abtestingClient';
5+
import { createAbtestingClient, REGIONS as abtestingRegions } from '{{{npmNamespace}}}/client-abtesting/src/abtestingClient';
6+
7+
import type { Region as PersonalizationRegion, PersonalizationClient } from '{{{npmNamespace}}}/client-personalization/src/personalizationClient';
8+
import { createPersonalizationClient, REGIONS as personalizationRegions } from '{{{npmNamespace}}}/client-personalization/src/personalizationClient';
9+
10+
import { createSearchClient, apiClientVersion as searchClientVersion } from '{{{npmNamespace}}}/client-search/src/searchClient';
11+
12+
import type { CreateClientOptions } from '{{{npmNamespace}}}/client-common';
13+
import { CommonInitOptions, InitRegion, CommonClientOptions } from "./models"
2014

2115
export * from './models';
2216

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,70 @@
1-
function initAnalytics(
2-
analyticsAppId: string,
3-
analyticsApiKey: string,
4-
region?: AnalyticsRegion,
5-
analyticsOptions?: { requester?: Requester; hosts?: Host[] }
6-
): AnalyticsClient {
1+
function initAnalytics(initOptions: CommonInitOptions & InitRegion<AnalyticsRegion> = {}): AnalyticsClient {
2+
if (
3+
initOptions.region &&
4+
(typeof initOptions.region !== 'string' ||
5+
!analyticsRegions.includes(initOptions.region))
6+
) {
7+
throw new Error(
8+
`\`region\` must be one of the following: ${analyticsRegions.join(', ')}`
9+
);
10+
}
11+
712
return createAnalyticsClient({
8-
appId: analyticsAppId,
9-
apiKey: analyticsApiKey,
10-
region,
11-
...analyticsOptions,
13+
...initOptions.options,
14+
...commonOptions,
15+
appId: initOptions.appId ?? appId,
16+
apiKey: initOptions.apiKey ?? apiKey,
17+
region: initOptions.region,
18+
});
19+
}
20+
21+
function initAbtesting(initOptions: CommonInitOptions & InitRegion<AbtestingRegion> = {}): AbtestingClient {
22+
if (
23+
initOptions.region &&
24+
(typeof initOptions.region !== 'string' ||
25+
!abtestingRegions.includes(initOptions.region))
26+
) {
27+
throw new Error(
28+
`\`region\` must be one of the following: ${abtestingRegions.join(', ')}`
29+
);
30+
}
31+
32+
return createAbtestingClient({
33+
...initOptions.options,
1234
...commonOptions,
35+
appId: initOptions.appId ?? appId,
36+
apiKey: initOptions.apiKey ?? apiKey,
37+
region: initOptions.region,
1338
});
1439
}
1540

16-
function initPersonalization(
17-
personalizationAppId: string,
18-
personalizationApiKey: string,
19-
region: PersonalizationRegion,
20-
personalizationOptions?: { requester?: Requester; hosts?: Host[] }
21-
): PersonalizationClient {
22-
if (!region) {
41+
function initPersonalization(initOptions: CommonInitOptions & Required<InitRegion<PersonalizationRegion>>): PersonalizationClient {
42+
if (!initOptions.region) {
2343
throw new Error('`region` is missing.');
2444
}
2545

46+
if (
47+
initOptions.region &&
48+
(typeof initOptions.region !== 'string' ||
49+
!personalizationRegions.includes(initOptions.region))
50+
) {
51+
throw new Error(
52+
`\`region\` must be one of the following: ${personalizationRegions.join(', ')}`
53+
);
54+
}
55+
2656
return createPersonalizationClient({
27-
appId: personalizationAppId,
28-
apiKey: personalizationApiKey,
29-
region,
30-
...personalizationOptions,
57+
...initOptions.options,
3158
...commonOptions,
59+
appId: initOptions.appId ?? appId,
60+
apiKey: initOptions.apiKey ?? apiKey,
61+
region: initOptions.region,
3262
});
3363
}
3464

3565
return {
3666
...createSearchClient({ appId, apiKey, ...commonOptions }),
3767
initAnalytics,
3868
initPersonalization,
69+
initAbtesting,
3970
};

templates/javascript/clients/algoliasearch/builds/models.mustache

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import type {
2+
Host,
3+
Requester,
4+
} from '{{{npmNamespace}}}/client-common';
15
import {
26
ErrorBase,
37
PutProps,
@@ -9,5 +13,27 @@ import {
913
export * from '{{{npmNamespace}}}/client-search/model';
1014
export * from '{{{npmNamespace}}}/client-personalization/model';
1115
export * from '{{{npmNamespace}}}/client-analytics/model';
16+
export * from '{{{npmNamespace}}}/client-abtesting/model';
1217

1318
export { ErrorBase, PutProps, PostProps, DelProps, GetProps };
19+
20+
export type CommonClientOptions = { requester?: Requester; hosts?: Host[] };
21+
22+
export type CommonInitOptions = Partial<{
23+
/**
24+
* App to target with the initialized client, defaults to the `algoliasearch` appId.
25+
*/
26+
appId: string;
27+
/**
28+
* API key of the targeted app ID, defaults to the `algoliasearch` apiKey.
29+
*/
30+
apiKey: string;
31+
options: CommonClientOptions;
32+
}>;
33+
34+
export type InitRegion<TRegion> = Partial<{
35+
/**
36+
* Available regions of the initialized client.
37+
*/
38+
region: TRegion;
39+
}>;

templates/javascript/clients/algoliasearch/builds/node.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { createHttpRequester } from '{{{npmNamespace}}}/requester-node-http';
1414
export function algoliasearch(
1515
appId: string,
1616
apiKey: string,
17-
options?: { requester?: Requester; hosts?: Host[] }
17+
options?: CommonClientOptions
1818
) {
1919
{{> algoliasearch/builds/checkParameters}}
2020

0 commit comments

Comments
 (0)