Skip to content

Commit 8323151

Browse files
committed
feat(javascript): add waitForApiKey helper method
1 parent d7fcc6d commit 8323151

File tree

7 files changed

+165
-29
lines changed

7 files changed

+165
-29
lines changed

templates/javascript/api-single.mustache

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export function create{{capitalizedApiName}}({
1818
hosts: getDefaultHosts({{^hasRegionalHost}}appIdOption{{/hasRegionalHost}}{{#hasRegionalHost}}regionOption{{/hasRegionalHost}}),
1919
...options,
2020
algoliaAgent: getAlgoliaAgent({
21-
algoliaAgents: algoliaAgents,
21+
algoliaAgents,
2222
client: '{{{algoliaAgent}}}',
2323
version: apiClientVersion,
2424
}),
@@ -39,32 +39,7 @@ export function create{{capitalizedApiName}}({
3939

4040
return {
4141
addAlgoliaAgent,
42-
{{#isSearchClient}}
43-
/**
44-
* Wait for a task to complete with `indexName` and `taskID`.
45-
*
46-
* @summary Wait for a task to complete.
47-
* @param waitForTaskProps - The waitForTaskProps object.
48-
* @param waitForTaskProps.indexName - The index in which to perform the request.
49-
* @param waitForTaskProps.taskID - The unique identifier of the task to wait for.
50-
*/
51-
waitForTask({
52-
indexName,
53-
taskID,
54-
...createRetryablePromiseOptions,
55-
}: {
56-
indexName: string;
57-
taskID: number;
58-
} & Omit<CreateRetryablePromiseOptions<GetTaskResponse>, 'func' | 'validate'>): Promise<void> {
59-
return new Promise<void>((resolve, reject) => {
60-
createRetryablePromise<GetTaskResponse>({
61-
...createRetryablePromiseOptions,
62-
func: () => this.getTask({ indexName, taskID }),
63-
validate: (response) => response.status === 'published',
64-
}).then(() => resolve()).catch(reject);
65-
});
66-
},
67-
{{/isSearchClient}}
42+
{{#isSearchClient}}{{> api/helpers}}{{/isSearchClient}}
6843
{{#operation}}
6944
{{> api/operation/jsdoc}}
7045
{{nickname}}( {{> api/operation/parameters}} ) : Promise<{{{returnType}}}> {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* Helper: Wait for a task to complete with `indexName` and `taskID`.
3+
*
4+
* @summary Wait for a task to complete.
5+
* @param waitForTaskOptions - The waitForTaskOptions object.
6+
* @param waitForTaskOptions.indexName - The `indexName` where the operation was performed.
7+
* @param waitForTaskOptions.taskID - The `taskID` returned in the method response.
8+
*/
9+
waitForTask({
10+
indexName,
11+
taskID,
12+
...createRetryablePromiseOptions
13+
}: WaitForTaskOptions): Promise<GetTaskResponse> {
14+
return createRetryablePromise({
15+
...createRetryablePromiseOptions,
16+
func: () => this.getTask({ indexName, taskID }),
17+
validate: (response) => response.status === 'published',
18+
});
19+
},
20+
/**
21+
* Helper: Wait for an API key to be valid, updated or deleted based on a given `operation`.
22+
*
23+
* @summary Wait for an API key task to be processed.
24+
* @param waitForApiKeyOptions - The waitForApiKeyOptions object.
25+
* @param waitForApiKeyOptions.operation - The `operation` that was done on a `key`.
26+
* @param waitForApiKeyOptions.key - The `key` that has been added, deleted or updated.
27+
* @param waitForApiKeyOptions.apiKey - Necessary to know if an `update` operation has been processed, compare fields of the response with it.
28+
*/
29+
waitForApiKey({
30+
operation,
31+
key,
32+
apiKey,
33+
...createRetryablePromiseOptions
34+
}: WaitForApiKeyOptions): Promise<ApiError | Key> {
35+
if (operation === 'update') {
36+
const validate = (response: ApiKey): boolean => {
37+
for (const [entry, values] of Object.entries(apiKey)) {
38+
if (Array.isArray(values)) {
39+
if (
40+
values.length === response[entry].length &&
41+
values.every((val, index) => val === response[entry][index])
42+
) {
43+
return true;
44+
}
45+
} else if (values === response[entry]) {
46+
return true;
47+
}
48+
}
49+
50+
return false;
51+
};
52+
53+
return createRetryablePromise({
54+
...createRetryablePromiseOptions,
55+
func: () => this.getApiKey({ key }),
56+
validate,
57+
});
58+
}
59+
60+
return createRetryablePromise({
61+
...createRetryablePromiseOptions,
62+
func: () => this.getApiKey({ key }).catch((error) => error),
63+
validate: (error: ApiError) =>
64+
operation === 'add' ? error.status !== 404 : error.status === 404,
65+
});
66+
},

templates/javascript/api/imports.mustache

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import type {
1515
RequestOptions,
1616
QueryParameters,
1717
{{#isSearchClient}}
18-
CreateRetryablePromiseOptions,
18+
ApiError,
1919
{{/isSearchClient}}
2020
} from '{{{npmNamespace}}}/client-common';
2121

@@ -25,6 +25,10 @@ import { {{classname}} } from '{{filename}}';
2525

2626
{{#operations}}
2727
import type {
28+
{{#isSearchClient}}
29+
WaitForTaskOptions,
30+
WaitForApiKeyOptions,
31+
{{/isSearchClient}}
2832
{{#operation}}
2933
{{#vendorExtensions}}
3034
{{#x-create-wrapping-object}}

templates/javascript/clientMethodProps.mustache

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import { {{classname}} } from '{{filename}}';
77
{{! Imports for the legacy search method signature }}
88
{{#operations}}{{#operation}}{{#vendorExtensions.x-legacy-signature}}{{> api/operation/legacySearchCompatible/imports}}{{/vendorExtensions.x-legacy-signature}}{{/operation}}{{/operations}}
99

10+
{{! Imports for the helpers method of the search client }}
11+
{{#isSearchClient}}import type { CreateRetryablePromiseOptions } from '@experimental-api-clients-automation/client-common';{{/isSearchClient}}
12+
1013
{{#operations}}
1114
{{#operation}}
1215

@@ -33,4 +36,48 @@ export type {{#lambda.titlecase}}{{nickname}}{{/lambda.titlecase}}Props = {
3336

3437
{{/operation}}
3538
{{/operations}}
39+
40+
{{#isSearchClient}}
41+
type WaitForOptions<T> = Omit<
42+
CreateRetryablePromiseOptions<T>,
43+
'func' | 'validate'
44+
>;
45+
46+
export type WaitForTaskOptions = WaitForOptions<GetTaskResponse> & {
47+
/**
48+
* The `indexName` where the operation was performed.
49+
*/
50+
indexName: string;
51+
/**
52+
* The `taskID` returned by the method response.
53+
*/
54+
taskID: number;
55+
};
56+
57+
export type WaitForApiKeyOptions = WaitForOptions<Key> & {
58+
/**
59+
* The API Key.
60+
*/
61+
key: string;
62+
} & (
63+
| {
64+
/**
65+
* The operation that has been performed, used to compute the stop condition.
66+
*/
67+
operation: 'add' | 'delete';
68+
apiKey?: never;
69+
}
70+
| {
71+
/**
72+
* The operation that has been performed, used to compute the stop condition.
73+
*/
74+
operation: 'update';
75+
/**
76+
* The updated fields, used to compute the stop condition.
77+
*/
78+
apiKey: Partial<ApiKey>;
79+
}
80+
);
81+
{{/isSearchClient}}
82+
3683
{{/apiInfo.apis.0}}

website/docs/clients/guides/copy-index-to-another-application.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: Copy or move an index
2+
title: Copy an index to another application
33
---
44

55
:::caution
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
title: Wait for an API key to be valid
3+
---
4+
5+
import { TabsLanguage } from '../../../src/components/TabsLanguage';
6+
import TabItem from '@theme/TabItem';
7+
8+
> The `waitForApiKey` method is only available in the `search` client context.
9+
10+
Adding, updating or deleting API keys is not always instantaneous, which is why you might want to ensure the job has been processed before jumping to an other task.
11+
12+
We provide a `waitForApiKey` helper method for you to easily wait for a specific `operation` made on a `key`.
13+
14+
> An `operation` can either be `add` | `update` | `delete`
15+
16+
<TabsLanguage>
17+
<TabItem value="javascript">
18+
19+
```js
20+
import { algoliasearch } from '@experimental-api-clients-automation/algoliasearch';
21+
22+
const client = algoliasearch('<YOUR_APP_ID>', '<YOUR_API_KEY>');
23+
24+
const { key } = await client.addApiKey({
25+
acl: ['analytics', 'browse', 'editSettings'],
26+
});
27+
28+
// Poll the task status with defaults values
29+
await client.waitForApiKey({ operation: 'add', key });
30+
31+
// Poll the task status with your options
32+
await client.waitForTask({
33+
operation: 'add',
34+
key,
35+
// Number of maximum retries to do
36+
maxRetries: 100,
37+
// The time to wait between tries
38+
timeout: (retryCount: number): number => Math.min(retryCount * 200, 5000),
39+
});
40+
```
41+
42+
</TabItem>
43+
</TabsLanguage>

website/sidebars.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ const sidebars = {
7979
'clients/guides/retrieving-facets',
8080
'clients/guides/customized-client-usage',
8181
'clients/guides/wait-for-a-task-to-finish',
82+
'clients/guides/wait-for-api-key-to-be-valid',
8283
'clients/guides/copy-or-move-index',
8384
'clients/guides/copy-index-to-another-application',
8485
],

0 commit comments

Comments
 (0)