diff --git a/src/resource_clients/key_value_store.ts b/src/resource_clients/key_value_store.ts index 4c56d844..3fec5afe 100644 --- a/src/resource_clients/key_value_store.ts +++ b/src/resource_clients/key_value_store.ts @@ -70,6 +70,30 @@ export class KeyValueStoreClient extends ResourceClient { return cast(parseDateFields(pluckData(response.data))); } + /** + * Tests whether a record with the given key exists in the key-value store without retrieving its value. + * + * https://docs.apify.com/api/v2#/reference/key-value-stores/record/get-record + * @param key The queried record key. + * @returns `true` if the record exists, `false` if it does not. + */ + async recordExists(key: string): Promise { + const requestOpts: Record = { + url: this._url(`records/${key}`), + method: 'HEAD', + params: this._params(), + }; + + try { + await this.httpClient.call(requestOpts); + return true; + } catch (err) { + catchNotFoundOrThrow(err as ApifyApiError); + } + + return false; + } + /** * You can use the `buffer` option to get the value in a Buffer (Node.js) * or ArrayBuffer (browser) format. In Node.js (not in browser) you can also diff --git a/src/utils.ts b/src/utils.ts index c01455a5..1dcaff0c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -41,7 +41,7 @@ export function pluckData(obj: MaybeData): R { */ export function catchNotFoundOrThrow(err: ApifyApiError): void { const isNotFoundStatus = err.statusCode === NOT_FOUND_STATUS_CODE; - const isNotFoundMessage = err.type === RECORD_NOT_FOUND_TYPE || err.type === RECORD_OR_TOKEN_NOT_FOUND_TYPE; + const isNotFoundMessage = err.type === RECORD_NOT_FOUND_TYPE || err.type === RECORD_OR_TOKEN_NOT_FOUND_TYPE || err.httpMethod === 'head'; const isNotFoundError = isNotFoundStatus && isNotFoundMessage; if (!isNotFoundError) throw err; } diff --git a/test/key_value_stores.test.js b/test/key_value_stores.test.js index e0da49ff..718b68e3 100644 --- a/test/key_value_stores.test.js +++ b/test/key_value_stores.test.js @@ -143,6 +143,52 @@ describe('Key-Value Store methods', () => { validateRequest(query, { storeId }); }); + test('recordExists() works', async () => { + const key = 'some-key'; + const storeId = 'some-id'; + + const expectedBody = null; + const expectedContentType = 'application/json; charset=utf-8'; + const expectedHeaders = { + 'content-type': expectedContentType, + }; + + mockServer.setResponse({ headers: expectedHeaders, body: expectedBody, status: 200 }); + + const res = await client.keyValueStore(storeId).recordExists(key); + const expectedResult = true; + + expect(res).toEqual(expectedResult); + validateRequest({}, { storeId, key }); + + const browserRes = await page.evaluate((id, k) => client.keyValueStore(id).recordExists(k), storeId, key); + expect(browserRes).toEqual(res); + validateRequest({}, { storeId, key }); + }); + + test('recordExists() works with a missing record', async () => { + const key = 'missing-key'; + const storeId = 'some-id'; + + const expectedBody = null; + const expectedContentType = 'application/json; charset=utf-8'; + const expectedHeaders = { + 'content-type': expectedContentType, + }; + + mockServer.setResponse({ headers: expectedHeaders, body: expectedBody, statusCode: 404 }); + + const res = await client.keyValueStore(storeId).recordExists(key); + const expectedResult = false; + + expect(res).toEqual(expectedResult); + validateRequest({}, { storeId, key }); + + const browserRes = await page.evaluate((id, k) => client.keyValueStore(id).recordExists(k), storeId, key); + expect(browserRes).toEqual(res); + validateRequest({}, { storeId, key }); + }); + test('getRecord() works', async () => { const key = 'some-key'; const storeId = 'some-id';