diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index bde5b1b98..388931623 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -549,6 +549,8 @@ faceted_search_1: |- client.index('books').search('classic', { facets: ['genres', 'rating', 'language'] }) post_dump_1: |- client.createDump() +create_snapshot_1: |- + client.createSnapshot() phrase_search_1: |- client.index('movies') .search('"african american" horror') diff --git a/README.md b/README.md index 49d85101d..4d9651661 100644 --- a/README.md +++ b/README.md @@ -1039,6 +1039,13 @@ client.getVersion(): Promise client.createDump(): Promise ``` +### Snapshots + +#### [Trigger a snapshot on-demand process](https://www.meilisearch.com/docs/reference/api/snapshots#create-a-snapshot) + +```ts +client.createSnapshot(): Promise +``` --- Meilisearch provides and maintains many SDKs and integration tools like this one. We want to provide everyone with an **amazing search experience for any kind of project**. For a full overview of everything we create and maintain, take a look at the [integration-guides](https://github.com/meilisearch/integration-guides) repository. diff --git a/src/clients/client.ts b/src/clients/client.ts index 416675dd8..3cd9c6b74 100644 --- a/src/clients/client.ts +++ b/src/clients/client.ts @@ -443,6 +443,22 @@ class Client { return new EnqueuedTask(task) } + /// + /// SNAPSHOTS + /// + + /** + * Creates a snapshot + * + * @returns Promise returning object of the enqueued task + */ + async createSnapshot(): Promise { + const url = `snapshots` + const task = await this.httpRequest.post(url) + + return new EnqueuedTask(task) + } + /// /// TOKENS /// diff --git a/tests/snapshots.test.ts b/tests/snapshots.test.ts new file mode 100644 index 000000000..b77e20bf7 --- /dev/null +++ b/tests/snapshots.test.ts @@ -0,0 +1,70 @@ +import { ErrorStatusCode } from '../src/types' +import { + clearAllIndexes, + config, + MeiliSearch, + BAD_HOST, + getClient, +} from './utils/meilisearch-test-utils' + +beforeEach(async () => { + await clearAllIndexes(config) +}) + +describe.each([{ permission: 'Master' }, { permission: 'Admin' }])( + 'Test on snapshot', + ({ permission }) => { + test(`${permission} key: create a new snapshot`, async () => { + const client = await getClient(permission) + const { taskUid } = await client.createSnapshot() + + await client.waitForTask(taskUid) + }) + } +) + +describe.each([{ permission: 'Search' }])( + 'Test on snapshot with search api key should not have access', + ({ permission }) => { + test(`${permission} key: try to create snapshot with search key and be denied`, async () => { + const client = await getClient(permission) + await expect(client.createSnapshot()).rejects.toHaveProperty( + 'code', + ErrorStatusCode.INVALID_API_KEY + ) + }) + } +) + +describe.each([{ permission: 'No' }])( + 'Test on snapshot without api key should not have access', + ({ permission }) => { + test(`${permission} key: try to create snapshot with no key and be denied`, async () => { + const client = await getClient(permission) + await expect(client.createSnapshot()).rejects.toHaveProperty( + 'code', + ErrorStatusCode.MISSING_AUTHORIZATION_HEADER + ) + }) + } +) + +describe.each([ + { host: BAD_HOST, trailing: false }, + { host: `${BAD_HOST}/api`, trailing: false }, + { host: `${BAD_HOST}/trailing/`, trailing: true }, +])('Tests on url construction', ({ host, trailing }) => { + test(`Test createSnapshot route`, async () => { + const route = `snapshots` + const client = new MeiliSearch({ host }) + const strippedHost = trailing ? host.slice(0, -1) : host + + await expect(client.createSnapshot()).rejects.toHaveProperty( + 'message', + `request to ${strippedHost}/${route} failed, reason: connect ECONNREFUSED ${BAD_HOST.replace( + 'http://', + '' + )}` + ) + }) +})