Skip to content

Migrate V2 /update endpoints to using JAX-RS#4177

Draft
epugh wants to merge 16 commits intoapache:mainfrom
epugh:copilot/migrate-update-api-to-jax-rs
Draft

Migrate V2 /update endpoints to using JAX-RS#4177
epugh wants to merge 16 commits intoapache:mainfrom
epugh:copilot/migrate-update-api-to-jax-rs

Conversation

@epugh
Copy link
Contributor

@epugh epugh commented Mar 2, 2026

This PR migrates the V2 /update endpoints to using JAX-RS.

This did require adding the /c/ path support to our JAX-RS support, so that is buried in here. We may rip it out or rename it, there is a ticket https://issues.apache.org/jira/browse/SOLR-11013 out there that refers to this.

The V2 JAX-RS update API has meaningful behavioral differences from V1 update handlers that aren't documented anywhere in the Ref Guide. So I added a new documentation page that is specific to V2, unlike our previous patterns of having both v1 and v2 documented next to each other.

New: indexing-with-v2-apis.adoc

Documents the V2 update endpoints with emphasis on the critical behavioral difference: /update and /update/json in V2 are document-only — they rewrite internally to /update/json/docs and do not support the JSON update command syntax (commit/delete/optimize in the request body). Full comparison:

Feature V1 V2
Base path /solr/{collection}/update /api/collections/{collection}/update
JSON documents /update or /update/json/docs /update or /update/json
JSON update commands /update not supported via /update or /update/json
XML updates /update (via Content-Type) /update/xml
CSV updates /update/csv /update/csv
JavaBin updates /update (via Content-Type) /update/bin

Someday, I wonder if we do want to re-instate the multiple commands support like we have in v1, but that would be expanding on what the existing v2 /update does. I think we would need to do that to retire the v1 version.

Copilot AI and others added 14 commits March 1, 2026 13:45
- Add UpdateApi JAX-RS interface in solr/api module with @path, @post,
  @operation annotations for /update, /update/json, /update/xml,
  /update/csv, /update/bin endpoints
- Rewrite UpdateAPI as a JerseyResource implementing UpdateApi;
  delegates to UpdateRequestHandler; adds UpdateRequestHandlerConfig
  inner class (APIConfigProvider.APIConfig) for injection
- Update V2UpdateRequestHandler to implement APIConfigProvider and
  use getJerseyResources() instead of getApis()
- Replace mock-based V2UpdateAPIMappingTest with UpdateAPITest
  integration test using SolrJettyTestRule

Co-authored-by: epugh <22395+epugh@users.noreply.github.com>
Resolves failing test: NodeHealthAPITest2.testLegacyMode_WithoutMaxGenerationLagReturnsOk

The test verifies that the V2 GET /api/node/health endpoint returns
status=OK in legacy (standalone, non-ZooKeeper) mode when maxGenerationLag
is not specified in the request. This exercises the null-maxGenerationLag
code path in HealthCheckHandler.healthCheckLegacyMode() which immediately
returns OK without checking replication lag.

Test uses SolrJettyTestRule with no ZooKeeper to run in legacy mode.

Co-authored-by: epugh <22395+epugh@users.noreply.github.com>
…n V2Request update/json

The V2Request("/c/{collection}/update/json") call was broken after the UpdateAPI
migration to JAX-RS: the JAX-RS path regex "cores|collections" doesn't match
the "/c/" alias. Replace with the proper SolrJ cloudClient.add() (which goes
through the v1 /update path) and update span name/collection assertions to match.

Co-authored-by: epugh <22395+epugh@users.noreply.github.com>
Normalize /c/ → /collections/ in ContainerRequestUtils.getRequestUri() before
Jersey sees the URI, fixing JAX-RS path matching for all endpoints that use
INDEX_PATH_PREFIX (update, select, schema, etc.) with the /c/ shorthand.

The tracing span name correctly preserves /c/{collection}/... since it is
computed from V2HttpCall.pathSegments which use the original request path.

Co-authored-by: epugh <22395+epugh@users.noreply.github.com>
…o UpdateRequestHandler

DistributedZkUpdateProcessor.handleReplicationFactor() calls
rsp.getResponseHeader().add(...), which requires the response header to be
initialized by SolrCore.preDecorateResponse(). In the JAX-RS path, this
was never called (only the old Api path calls it in executeCoreRequest).

Add pre/postDecorateResponse calls around the updateRequestHandler.handleRequest()
call in UpdateAPI.handleUpdate(), mirroring what SolrCore.execute() does for v1.

Co-authored-by: epugh <22395+epugh@users.noreply.github.com>
Co-authored-by: epugh <22395+epugh@users.noreply.github.com>
@github-actions github-actions bot added documentation Improvements or additions to documentation tests cat:api labels Mar 2, 2026
@epugh epugh requested a review from Copilot March 2, 2026 18:15
@epugh epugh changed the title docs: Add indexing-with-v2-apis.adoc for V2 /update API endpoints Migrate V2 /update endpoints to using JAX-RS Mar 2, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds Ref Guide documentation for Solr’s V2 update endpoints and (in the same change set) migrates the V2 /update implementation to a JAX-RS resource, including URI normalization to support the /c/ collection shorthand in Jersey routing.

Changes:

  • Added a new Ref Guide page documenting V2 update endpoints and their behavior vs V1 update handlers.
  • Updated indexing guide navigation to include and cross-reference the new V2 update documentation.
  • Switched V2 update handling to a Jersey resource + added /c//collections/ URI normalization, along with updated tests and a new OpenAPI endpoint interface.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
solr/solr-ref-guide/modules/indexing-guide/pages/indexing-with-v2-apis.adoc New V2 update API documentation and V1↔V2 comparison.
solr/solr-ref-guide/modules/indexing-guide/pages/indexing-with-update-handlers.adoc Cross-reference note + page-children update for new V2 page.
solr/solr-ref-guide/modules/indexing-guide/indexing-nav.adoc Adds the new V2 page to the indexing sidebar nav.
solr/core/src/java/org/apache/solr/jersey/container/ContainerRequestUtils.java Normalizes /c/ collection shorthand for Jersey path matching.
solr/core/src/java/org/apache/solr/handler/admin/api/UpdateAPI.java New Jersey-based V2 update resource delegating to UpdateRequestHandler.
solr/core/src/java/org/apache/solr/handler/V2UpdateRequestHandler.java Registers UpdateAPI as a Jersey resource and provides config injection.
solr/api/src/java/org/apache/solr/client/api/endpoint/UpdateApi.java New OpenAPI/JAX-RS endpoint interface for v2 update paths.
solr/core/src/test/org/apache/solr/handler/V2UpdateAPIMappingTest.java Removes old unit test for v2→v1 update path rewriting.
solr/core/src/test/org/apache/solr/handler.admin.api/UpdateAPITest.java Adds integration tests covering V2 update endpoints.
Comments suppressed due to low confidence (1)

solr/solr-ref-guide/modules/indexing-guide/pages/indexing-with-v2-apis.adoc:136

  • Capitalization of “Javabin” here (and in the table / comparison section) is inconsistent with the rest of the ref guide, which uses “JavaBin”. Please standardize on “JavaBin” (while keeping the MIME type application/javabin as-is).
== Javabin Document Indexing

The v2 `/update/bin` endpoint accepts documents in Javabin format, which is the native binary format used by SolrJ.
This endpoint is primarily intended for use by SolrJ clients.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +93 to +95
SolrCore.preDecorateResponse(solrQueryRequest, solrQueryResponse);
updateRequestHandler.handleRequest(solrQueryRequest, solrQueryResponse);
SolrCore.postDecorateResponse(updateRequestHandler, solrQueryRequest, solrQueryResponse);
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

handleUpdate calls SolrCore.postDecorateResponse(...), which adds a responseHeader to solrQueryResponse. The Jersey layer then serializes the returned SolrJerseyResponse by squashing it into the same SolrQueryResponse (also including its own responseHeader), which can result in duplicate responseHeader entries in the output. Consider removing the explicit pre/post decoration here (to align with other Jersey resources) or otherwise ensure only one responseHeader is serialized (e.g., clear the existing header before returning, or use a squash-without-header approach for this endpoint).

Suggested change
SolrCore.preDecorateResponse(solrQueryRequest, solrQueryResponse);
updateRequestHandler.handleRequest(solrQueryRequest, solrQueryResponse);
SolrCore.postDecorateResponse(updateRequestHandler, solrQueryRequest, solrQueryResponse);
// Do not call SolrCore.preDecorateResponse/postDecorateResponse here:
// Jersey will handle response decoration (including responseHeader) to avoid duplicates.
updateRequestHandler.handleRequest(solrQueryRequest, solrQueryResponse);

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

one of the tests was failing with out this...

Comment on lines +31 to +44
@POST
@StoreApiParameters
@Operation(
summary = "Add, delete, or update documents using any supported content type",
tags = {"update"})
SolrJerseyResponse update() throws Exception;

@POST
@Path("/json")
@StoreApiParameters
@Operation(
summary = "Add, delete, or update documents in JSON format",
tags = {"update"})
SolrJerseyResponse updateJson() throws Exception;
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

The OpenAPI summaries for /update and /update/json currently say they can “Add, delete, or update” and (for /update) accept “any supported content type”. In this PR’s implementation these endpoints are rewritten to /update/json/docs (docs-only JSON loader) and do not support JSON update commands in the request body, nor non-JSON bodies. Please update the summaries to match actual behavior so generated docs/clients don’t advertise unsupported operations.

Copilot uses AI. Check for mistakes.
Comment on lines +54 to +68
@POST
@Path("/csv")
@StoreApiParameters
@Operation(
summary = "Add, delete, or update documents in CSV format",
tags = {"update"})
SolrJerseyResponse updateCsv() throws Exception;

@POST
@Path("/bin")
@StoreApiParameters
@Operation(
summary = "Add, delete, or update documents in JavaBin format",
tags = {"update"})
SolrJerseyResponse updateBin() throws Exception;
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

Similarly, the summaries for /update/csv and /update/bin say “Add, delete, or update documents…”, but these loaders are document-ingest only (no delete/commit commands in-body). Please tighten the wording (e.g., “index documents”) to avoid implying full update-command support for these content types.

Copilot uses AI. Check for mistakes.
epugh and others added 2 commits March 3, 2026 08:18
…-v2-apis.adoc

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Contributor Author

@epugh epugh left a comment

Choose a reason for hiding this comment

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

This guy is tough!

public void testUpdateViaV2Api() throws Exception {
final SolrClient client = solrTestRule.getSolrClient(CORE_NAME);

// POST a JSON array of documents via the V2 /update endpoint (rewrites to /update/json/docs)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

While we CAN do it this way, can't we also do it with the solrj generaed code?

client.commit(CORE_NAME);

// Verify the document was indexed
final ModifiableSolrParams queryParams = new ModifiableSolrParams();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

is there a more concise way of doing this?

Comment on lines +93 to +95
SolrCore.preDecorateResponse(solrQueryRequest, solrQueryResponse);
updateRequestHandler.handleRequest(solrQueryRequest, solrQueryResponse);
SolrCore.postDecorateResponse(updateRequestHandler, solrQueryRequest, solrQueryResponse);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

one of the tests was failing with out this...


== Javabin Document Indexing

The v2 `/update/bin` endpoint accepts documents in Javabin format, which is the native binary format used by SolrJ.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

should this be /update/javabin ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cat:api documentation Improvements or additions to documentation tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants