Skip to content

Align ThrowExceptions decision with ProductRegistration.IsValidResponse#208

Merged
flobernd merged 1 commit into
mainfrom
fix/align-throw-with-isvalidresponse
Apr 27, 2026
Merged

Align ThrowExceptions decision with ProductRegistration.IsValidResponse#208
flobernd merged 1 commit into
mainfrom
fix/align-throw-with-isvalidresponse

Conversation

@flobernd
Copy link
Copy Markdown
Member

Summary

The throw decision in RequestPipeline.CreateClientException previously used HasSuccessfulStatusCodeAndExpectedContentType, which doesn't account for product-specific semantics like Elasticsearch's "404 with no extracted server error is a valid missing-entity response". This PR moves the predicate into a new virtual on ProductRegistration so each product encodes its own semantics, and consults it from both the throw path and the per-response IsValidResponse properties — single source of truth.

ElasticsearchProductRegistration.IsValidResponse now carries the verbatim logic that lived in the static ElasticsearchResponseHelper.IsValidResponse (now removed); the response-level IsValidResponse properties on the six Elasticsearch response types read it through ApiCallDetails.TransportConfiguration.ProductRegistration. The default ProductRegistration.IsValidResponse keeps the previous transport behavior (HasSuccessfulStatusCodeAndExpectedContentType) so non-product calls are unchanged.

Fixes #206. Pairs with the corresponding removal of ElasticsearchClientProductRegistration overrides in elasticsearch-net.

What changed

  • New public virtual bool IsValidResponse(ApiCallDetails?) on ProductRegistration. Default: details?.HasSuccessfulStatusCodeAndExpectedContentType ?? false.
  • ElasticsearchProductRegistration.IsValidResponse override carries the verbatim 404-lenient logic moved from the helper.
  • RequestPipeline.CreateClientException consults _productRegistration.IsValidResponse(callDetails) instead of the previous predicate.
  • Six Elasticsearch response types (ElasticsearchResponse, ElasticsearchDynamicResponse, ElasticsearchJsonResponse, ElasticsearchPipeResponse, ElasticsearchStreamResponse, ElasticsearchStringResponse) read the predicate via ApiCallDetails.TransportConfiguration.ProductRegistration.
  • ElasticsearchResponseHelper.IsValidResponse(ApiCallDetails?) deleted; the four other helpers stay.

Behavior change

Under ThrowExceptions=true:

  • Real-error 4xx/5xx still throw (unchanged for non-Elasticsearch users; newly correct for Elasticsearch users where the now-removed client-side HttpStatusCodeClassifier override had been suppressing throws on real-error 404s).
  • Valid 404s — e.g. client.GetAsync<MyDoc>(idx, missing-id) returning {"_index":"…","_id":"…","found":false} — no longer throw and instead return a response with IsValidResponse=true and Found=false.

Under the default ThrowExceptions=false, behavior is unchanged.

Tests

tests/Elastic.Transport.Tests/Products/ProductRegistrationIsValidResponseTests.cs — nine focused tests covering DefaultProductRegistration and ElasticsearchProductRegistration across 200/404/500 with/without extracted ProductError and with/without expected content type.

The throw decision in `RequestPipeline.CreateClientException` previously
used `HasSuccessfulStatusCodeAndExpectedContentType`, which doesn't
account for product-specific semantics like Elasticsearch's "404 with
no extracted server error is a valid missing-entity response". Move the
predicate into a new virtual method on `ProductRegistration` so each
product encodes its own semantics, and consult it from both the throw
path and the per-response `IsValidResponse` properties — single source
of truth.

`ElasticsearchProductRegistration.IsValidResponse` carries the verbatim
logic that lived in the static `ElasticsearchResponseHelper.IsValidResponse`
(now removed); the response-level `IsValidResponse` properties on the
six Elasticsearch response types now read it through
`ApiCallDetails.TransportConfiguration.ProductRegistration`. The default
`ProductRegistration.IsValidResponse` keeps the previous transport
behavior (`HasSuccessfulStatusCodeAndExpectedContentType`) so non-product
calls are unchanged.

Behavior change for users with `ThrowExceptions=true`:

- Real-error 4xx/5xx still throw (unchanged for non-Elasticsearch users;
  newly correct for Elasticsearch users where the now-removed client-
  side `HttpStatusCodeClassifier` override had been suppressing throws
  on real-error 404s).
- Valid 404s — e.g. `client.GetAsync<MyDoc>(idx, missing-id)` returning
  `{"_index":"…","_id":"…","found":false}` — no longer throw and instead
  return a response with `IsValidResponse=true` and `Found=false`.

Fixes elastic/elastic-transport-net#206. Pairs with elasticsearch-net's
removal of `ElasticsearchClientProductRegistration` overrides.
Copy link
Copy Markdown
Member

@Mpdreamz Mpdreamz left a comment

Choose a reason for hiding this comment

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

Love it!

@flobernd flobernd merged commit 0ef60d5 into main Apr 27, 2026
7 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 v0.17.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants