Skip to content

Conversation

@ernestorbemx
Copy link
Contributor

@ernestorbemx ernestorbemx commented Aug 8, 2025

Pull Request

Related issue

Fixes #877

What does this PR do?

  • Implement Export API
  • The implementation is based on some other APIS like Dumps API
  • Integration tests for new Client#export method
  • Unit tests for newly created ExportRequest and ExportIndexFilter classes

PR checklist

Please check if your PR fulfills the following requirements:

  • Does this PR fix an existing issue, or have you listed the changes applied in the PR description (and why they are needed)?
  • Have you read the contributing guidelines?
  • Have you made sure that the title is accurate and descriptive of the changes?

Thank you so much for contributing to Meilisearch!

Summary by CodeRabbit

  • New Features
    • Added support for exporting documents between Meilisearch instances with configurable target, payload size, and per-index filters, plus option to override index settings.
  • Tests
    • Added integration and unit tests to validate export initiation, task tracking, and request serialization/behavior across scenarios.
  • Documentation
    • Added a new code sample demonstrating how to construct and execute an export request.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 8, 2025

Walkthrough

Adds support for Meilisearch /export API: new ExportRequest and ExportIndexFilter models, a public Client.export(ExportRequest) method, integration and unit tests, and a .code-samples.meilisearch.yaml example export_post_1.

Changes

Cohort / File(s) Change Summary
Export Feature: Core Implementation
src/main/java/com/meilisearch/sdk/Client.java, src/main/java/com/meilisearch/sdk/ExportRequest.java, src/main/java/com/meilisearch/sdk/ExportIndexFilter.java
Added Client.export(ExportRequest) method; added ExportRequest and ExportIndexFilter classes with Lombok builders/getters/setters and toString() JSON serialization.
Tests: Integration & Unit
src/test/java/com/meilisearch/integration/ClientTest.java, src/test/java/com/meilisearch/sdk/ExportRequestTest.java
Added integration test testExport() invoking client.export(...) and asserting task properties; added unit tests validating ExportRequest/ExportIndexFilter toString() outputs and getters.
Examples: Code Sample
.code-samples.meilisearch.yaml
Added export_post_1 example showing building an ExportRequest (indexes map with ExportIndexFilter) and calling client.export(request).

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant SDK as Java SDK
    participant Server as Meilisearch Server

    User->>SDK: Build ExportRequest (url, apiKey?, payloadSize?, indexes?)
    User->>SDK: call export(request)
    rect rgb(220,240,255)
      SDK->>Server: POST /export (body: ExportRequest JSON)
      Server-->>SDK: TaskInfo (enqueued)
    end
    SDK-->>User: return TaskInfo
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • brunoocasali

Poem

A rabbit taps keys with nimble paws,
Builds an ExportRequest, checks the laws.
Filters set and payloads bright,
Tasks enqueued and ready to flight.
Hop—data journeys through the night. 🐇

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Add support for export API" succinctly captures the primary change of the pull request, namely implementing the new export API in the Java client, and is clear, concise, and appropriately focused on the main feature.
Linked Issues Check ✅ Passed The pull request implements all coding tasks specified in linked issue #877 by adding the Client#export method, corresponding integration and unit tests, and the example code under export_post_1 in .code-samples.meilisearch.yaml, directly addressing the issue requirements.
Out of Scope Changes Check ✅ Passed All changes in this pull request are focused on adding the export API feature and its supporting classes, tests, and examples, with no modifications outside the scope of the linked issue objectives.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
.code-samples.meilisearch.yaml (1)

846-849: Fix builder usage: Lombok builders don't use setXxx(...).

ExportRequest.builder().setUrl(...) won’t compile. Lombok’s builder uses the field name as the setter, i.e. url(...).

Apply this diff:

-export_post_1: |-
-  ExportRequest request = ExportRequest.builder().setUrl("http://anothermeiliinstance:7070").build();
-  client.export(request);
+export_post_1: |-
+  ExportRequest request = ExportRequest.builder().url("http://anothermeiliinstance:7070").build();
+  client.export(request);
🧹 Nitpick comments (11)
src/main/java/com/meilisearch/sdk/Client.java (1)

221-231: Add input validation and fix minor Javadoc casing.

  • Validate request and request.url early to fail fast on misuse.
  • Javadoc: “Instances” -> “instances”.

Apply this diff:

-    /**
-     * Triggers the export of documents between Meilisearch Instances.
+    /**
+     * Triggers the export of documents between Meilisearch instances.
      *
      * @param request Export request parameters
      * @return Meilisearch API response as TaskInfo
      * @throws MeilisearchException if an error occurs
      * @see <a href="https://www.meilisearch.com/docs/reference/api/export">API specification</a>
      */
     public TaskInfo export(ExportRequest request) throws MeilisearchException {
-        return config.httpClient.post("/export", request, TaskInfo.class);
+        if (request == null) {
+            throw new IllegalArgumentException("ExportRequest must not be null");
+        }
+        if (request.getUrl() == null || request.getUrl().isEmpty()) {
+            throw new IllegalArgumentException("ExportRequest.url must not be null or empty");
+        }
+        return config.httpClient.post("/export", request, TaskInfo.class);
     }
src/test/java/com/meilisearch/integration/ClientTest.java (1)

325-329: Rename local variable for clarity.

Rename snapshot to exportTask to avoid confusion with snapshot tests.

-        Task snapshot = client.getTask(task.getTaskUid());
+        Task exportTask = client.getTask(task.getTaskUid());
 
-        assertThat(task.getStatus(), is(equalTo(TaskStatus.ENQUEUED)));
-        assertThat(snapshot.getType(), is(equalTo("export")));
+        assertThat(task.getStatus(), is(equalTo(TaskStatus.ENQUEUED)));
+        assertThat(exportTask.getType(), is(equalTo("export")));
src/main/java/com/meilisearch/sdk/ExportIndexFilter.java (2)

15-19: Fix Javadoc class name.

This Javadoc refers to ExportRequest; it should reference ExportIndexFilter.

-    /**
-     * Method that returns the JSON String of the ExportRequest
+    /**
+     * Method that returns the JSON String of the ExportIndexFilter
      *
-     * @return JSON String of the ExportRequest query
+     * @return JSON String of the ExportIndexFilter
      */

22-27: Only include overrideSettings when true (avoid noisy JSON).

The current code always emits "overrideSettings": false. Emit it only when true for cleaner payloads.

-        JSONObject jsonObject =
-                new JSONObject()
-                        .putOpt("filter", this.filter)
-                        .putOpt("overrideSettings", this.overrideSettings);
+        JSONObject jsonObject = new JSONObject();
+        if (this.filter != null) {
+            jsonObject.put("filter", this.filter);
+        }
+        if (this.overrideSettings) {
+            jsonObject.put("overrideSettings", true);
+        }
         return jsonObject.toString();
src/test/java/com/meilisearch/sdk/ExportRequestTest.java (7)

18-22: Avoid brittle JSON string equality; assert structure via JSONObject

Comparing the raw JSON string ties the test to key ordering. Parse and assert fields instead.

-        String expected = "{\"overrideSettings\":false}";
-        assertThat(filter.toString(), is(equalTo(expected)));
+        JSONObject json = new JSONObject(filter.toString());
+        assertThat(json.getBoolean("overrideSettings"), is(false));
+        assertThat(json.has("filter"), is(false));
         assertThat(filter.getFilter(), is(nullValue()));
         assertThat(filter.isOverrideSettings(), is(false));

27-30: Make filter serialization check order-agnostic

Same concern: compare JSON structurally to avoid depending on key order.

-        String expected = "{\"overrideSettings\":true}";
-        assertThat(filter.toString(), is(equalTo(expected)));
+        JSONObject json = new JSONObject(filter.toString());
+        assertThat(json.getBoolean("overrideSettings"), is(true));
+        assertThat(json.has("filter"), is(false));
         assertThat(filter.isOverrideSettings(), is(true));

35-38: Assert JSON fields instead of exact string

Order of "filter" and "overrideSettings" should not matter; assert keys/values.

-        String expected = "{\"filter\":\"status = 'active'\",\"overrideSettings\":false}";
-        assertThat(filter.toString(), is(equalTo(expected)));
+        JSONObject json = new JSONObject(filter.toString());
+        assertThat(json.getString("filter"), is(equalTo("status = 'active'")));
+        assertThat(json.getBoolean("overrideSettings"), is(false));
         assertThat(filter.getFilter(), is(equalTo("status = 'active'")));

63-69: Replace JSON string equality with structural comparison

JSONObject.toString() can reorder keys. Use JSONObject#similar for semantic equality.

-        assertThat(expectedJson.toString(), is(json.toString()));
+        assertThat(json.similar(expectedJson), is(true));

70-77: Optional: assert absence rather than null for nested 'filter'

If the intended wire format omits nulls, assert absence to catch accidental inclusion of "filter": null.

-        assertThat(starIndex.isNull("filter"), is(true));
+        assertThat(starIndex.has("filter"), is(false));

If nulls are acceptable/desirable in payloads, keep the current check. Please confirm the expected API contract.


13-16: Clarify parity between toString() and HTTP serialization

Most tests validate toString()-produced JSON. Ensure the HTTP client uses the same serialization (key naming, null handling) to avoid divergences between unit tests and actual requests. If a different serializer (e.g., Gson/Jackson) is used, consider adding a serializer-focused test or aligning toString with it.

I can add a test that serializes via the actual HTTP layer to validate the final payload if desired.


45-47: Minor Hamcrest style nit (optional)

You can drop either is() or equalTo() for brevity without losing clarity: assertThat(x, is(y)) or assertThat(x, equalTo(y)).

Also applies to: 70-73, 95-97

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34e6053 and 0926b22.

📒 Files selected for processing (6)
  • .code-samples.meilisearch.yaml (1 hunks)
  • src/main/java/com/meilisearch/sdk/Client.java (1 hunks)
  • src/main/java/com/meilisearch/sdk/ExportIndexFilter.java (1 hunks)
  • src/main/java/com/meilisearch/sdk/ExportRequest.java (1 hunks)
  • src/test/java/com/meilisearch/integration/ClientTest.java (2 hunks)
  • src/test/java/com/meilisearch/sdk/ExportRequestTest.java (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/main/java/com/meilisearch/sdk/ExportIndexFilter.java (1)
src/main/java/com/meilisearch/sdk/ExportRequest.java (1)
  • Builder (7-33)
src/main/java/com/meilisearch/sdk/ExportRequest.java (1)
src/main/java/com/meilisearch/sdk/ExportIndexFilter.java (1)
  • Builder (6-28)
🔇 Additional comments (3)
src/main/java/com/meilisearch/sdk/Client.java (1)

229-231: API wiring looks correct.

The endpoint, payload type, and return type are consistent with other Client methods.

src/main/java/com/meilisearch/sdk/ExportRequest.java (1)

13-16: Fields conform to Meilisearch v1.16 Export API spec

All request‐body fields match the official spec for Meilisearch v1.16:

• src/main/java/com/meilisearch/sdk/ExportRequest.java
– url: String (required)
– apiKey: String (optional, accepts null)
– payloadSize: String (optional, human-readable with unit)
– indexes: Map<String,ExportIndexFilter> (optional)

• src/main/java/com/meilisearch/sdk/ExportIndexFilter.java
– filter: String (optional, null allowed)
– overrideSettings: boolean (optional, defaults to false)

No changes are needed.

src/test/java/com/meilisearch/sdk/ExportRequestTest.java (1)

44-49: Good: robust null checks for optional fields

Using JSONObject.isNull handles both absent and explicit null cases for apiKey/indexes. This keeps tests resilient across serializer strategies.

Comment on lines +25 to +31
JSONObject jsonObject =
new JSONObject()
.put("url", this.url)
.putOpt("apiKey", this.apiKey)
.putOpt("payloadSize", this.payloadSize)
.putOpt("indexes", this.indexes);
return jsonObject.toString();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Do not expose secrets in toString(); redact apiKey.

toString() is frequently logged. Emitting a raw API key is a security risk.

Apply this diff to redact the key:

-        JSONObject jsonObject =
-                new JSONObject()
-                        .put("url", this.url)
-                        .putOpt("apiKey", this.apiKey)
-                        .putOpt("payloadSize", this.payloadSize)
-                        .putOpt("indexes", this.indexes);
+        String redactedApiKey = (this.apiKey == null) ? null : "REDACTED";
+        JSONObject jsonObject =
+                new JSONObject()
+                        .put("url", this.url)
+                        .putOpt("apiKey", redactedApiKey)
+                        .putOpt("payloadSize", this.payloadSize)
+                        .putOpt("indexes", this.indexes);
         return jsonObject.toString();

If you need an unredacted JSON string for tests, consider adding a dedicated method like toJson(boolean redactSecrets) and update tests accordingly. I can draft that change and the test updates if you want.

🤖 Prompt for AI Agents
In src/main/java/com/meilisearch/sdk/ExportRequest.java around lines 25 to 31,
the toString() method currently includes the raw apiKey, which is a security
risk. Modify the method to redact the apiKey value by replacing it with a
placeholder like "REDACTED" before returning the JSON string. Alternatively,
create a new method such as toJson(boolean redactSecrets) that conditionally
redacts the apiKey, and update tests to use this method accordingly.

Copy link
Member

@curquiza curquiza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @ernestorbemx

Sorry for the delay
Can you fix the tests?


ExportRequestTest > toStringSimpleExportIndexFilter() FAILED
    java.lang.AssertionError: 
    Expected: is "{\"overrideSettings\":false}"
         but: was "{}"
        at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
        at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:6)
        at com.meilisearch.sdk.ExportRequestTest.toStringSimpleExportIndexFilter(ExportRequestTest.java:19)

ExportRequestTest > toStringExportIndexFilterWithFilter() FAILED
    java.lang.AssertionError: 
    Expected: is "{\"filter\":\"status = 'active'\",\"overrideSettings\":false}"
         but: was "{\"filter\":\"status = 'active'\"}"
        at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
        at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:6)
        at com.meilisearch.sdk.ExportRequestTest.toStringExportIndexFilterWithFilter(ExportRequestTest.java:36)

Gradle Test Executor 1 finished executing tests.

@ernestorbemx
Copy link
Contributor Author

@curquiza Oops, my bad, forgot to include tests too. It should be passing now.

@brunoocasali brunoocasali added the enhancement New feature or request label Sep 8, 2025
Copy link
Member

@curquiza curquiza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank youuu

bors merge

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
.code-samples.meilisearch.yaml (1)

850-854: Verify alignment with the documentation example.

Based on the past review comment, this code sample should reflect the example from the Meilisearch documentation. Please confirm that the current implementation matches the reference example linked in the previous review.

What is the structure of the export_post_1 example in the Meilisearch documentation at https://github.com/meilisearch/documentation/blob/f1562b2b98919c440f0fb124a5cfc8d66456e77b/.code-samples.meilisearch.yaml#L1470-L1481?
🧹 Nitpick comments (1)
src/test/java/com/meilisearch/integration/ClientTest.java (1)

316-330: Verify the export target URL in the integration test.

The test uses getMeilisearchHost() as the export target URL, which points to the same instance being tested. In a typical export scenario, you would export to a different Meilisearch instance. Please confirm whether:

  1. This is intentional for testing purposes (e.g., the export endpoint accepts the same instance as target in test scenarios)
  2. The export functionality is designed to handle self-exports
  3. A different URL should be used for a more realistic integration test

Additionally, consider verifying that the export task eventually reaches a terminal state (succeeded or failed) rather than just checking it was enqueued, to ensure the export actually processes the request correctly.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 071fb72 and ea1c43c.

📒 Files selected for processing (2)
  • .code-samples.meilisearch.yaml (1 hunks)
  • src/test/java/com/meilisearch/integration/ClientTest.java (2 hunks)
🔇 Additional comments (1)
src/test/java/com/meilisearch/integration/ClientTest.java (1)

10-11: LGTM!

The new imports for ExportIndexFilter, ExportRequest, HashMap, and Map are appropriate for the export test functionality being added.

Also applies to: 19-20

@curquiza curquiza merged commit 2c4ef64 into meilisearch:main Oct 7, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[v1.16] Add support for /export API

3 participants