Skip to content

Commit

Permalink
fix: handle errors in multisearch responses
Browse files Browse the repository at this point in the history
  • Loading branch information
cdmbr committed Nov 29, 2023
1 parent 617030d commit 03f5ec8
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -1,37 +1,41 @@
package com.sksamuel.elastic4s.requests.searches

import com.sksamuel.elastic4s.handlers.ElasticErrorParser
import com.sksamuel.elastic4s.json.XContentBuilder
import com.sksamuel.elastic4s.requests.common.IndicesOptionsParams
import com.sksamuel.elastic4s.requests.searches.aggs.AbstractAggregation
import com.sksamuel.elastic4s.{ElasticError, ElasticRequest, ElasticUrlEncoder, Handler, HttpEntity, HttpResponse, JacksonSupport, ResponseHandler}

trait SearchHandlers {

class BaseMultiSearchHandler(customAggregationHandler: PartialFunction[AbstractAggregation, XContentBuilder]) extends Handler[MultiSearchRequest, MultiSearchResponse] {
class BaseMultiSearchHandler(customAggregationHandler: PartialFunction[AbstractAggregation, XContentBuilder]) extends Handler[MultiSearchRequest, MultiSearchResponse] {

import scala.collection.JavaConverters._

override def responseHandler: ResponseHandler[MultiSearchResponse] = new ResponseHandler[MultiSearchResponse] {
override def handle(response: HttpResponse): Right[Nothing, MultiSearchResponse] = {
val json = JacksonSupport.mapper.readTree(response.entity.get.content)
val items = Option(json.get("responses")) match {
case Some(node) =>
node.elements
.asScala
.zipWithIndex
.map {
case (element, index) =>
val status = element.get("status").intValue()
val either =
if (element.has("error"))
Left(JacksonSupport.mapper.treeToValue[ElasticError](element.get("error")))
else
Right(JacksonSupport.mapper.treeToValue[SearchResponse](element))
MultisearchResponseItem(index, status, either)
}.toSeq
case None => Nil
}
Right(MultiSearchResponse(items))
override def handle(response: HttpResponse): Either[ElasticError, MultiSearchResponse] = response.statusCode match {
case status if status >= 200 && status < 300 =>
val json = JacksonSupport.mapper.readTree(response.entity.get.content)
val items = Option(json.get("responses")) match {
case Some(node) =>
node.elements
.asScala
.zipWithIndex
.map {
case (element, index) =>
val status = element.get("status").intValue()
val either =
if (element.has("error"))
Left(JacksonSupport.mapper.treeToValue[ElasticError](element.get("error")))
else
Right(JacksonSupport.mapper.treeToValue[SearchResponse](element))
MultisearchResponseItem(index, status, either)
}.toSeq
case None => Nil
}
Right(MultiSearchResponse(items))
case _ =>
Left(ElasticErrorParser.parse(response))
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.sksamuel.elastic4s.requests.searches

import com.sksamuel.elastic4s.HttpEntity.StringEntity
import com.sksamuel.elastic4s.requests.searches.SearchHandlers.MultiSearchHandler
import com.sksamuel.elastic4s.{ElasticError, HttpResponse}
import org.scalatest.EitherValues
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

class MultiSearchHandlerTest extends AnyFlatSpec with Matchers with EitherValues {

it should "handle error responses properly" in {
val responseBody = """{"error":{"type":"some_error_type","reason":"some_error_reason","root_cause":[]},"status":400}"""
val response = HttpResponse(400, Some(StringEntity(responseBody, None)), Map.empty)

MultiSearchHandler.responseHandler.handle(response).left.value shouldBe ElasticError("some_error_type", "some_error_reason", None, None, None, Seq.empty, None)
}

it should "handle successful responses properly" in {
val responseBody =
"""{
| "took": 1,
| "responses": [
| {
| "took": 1,
| "timed_out": false,
| "_shards": {
| "total": 1,
| "successful": 1,
| "skipped": 0,
| "failed": 0
| },
| "hits": {
| "total": {
| "value": 0,
| "relation": "eq"
| },
| "max_score": null,
| "hits": []
| },
| "status": 200
| },
| {
| "error": {
| "type": "some_error_type",
| "reason": "some_error_reason",
| "root_cause": []
| },
| "status": 400
| }
| ]
|}""".stripMargin
val response = HttpResponse(200, Some(StringEntity(responseBody, None)), Map.empty)
val mResponse = MultiSearchHandler.responseHandler.handle(response).right.value
mResponse.items should have size 2
mResponse.items.map(_.status) shouldEqual Seq(200, 400)
}
}

0 comments on commit 03f5ec8

Please sign in to comment.