diff --git a/elastic4s-core/src/main/scala/com/sksamuel/elastic4s/requests/searches/SearchHandlers.scala b/elastic4s-core/src/main/scala/com/sksamuel/elastic4s/requests/searches/SearchHandlers.scala index 52636bd8c..1121c8777 100644 --- a/elastic4s-core/src/main/scala/com/sksamuel/elastic4s/requests/searches/SearchHandlers.scala +++ b/elastic4s-core/src/main/scala/com/sksamuel/elastic4s/requests/searches/SearchHandlers.scala @@ -1,5 +1,6 @@ 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 @@ -7,31 +8,34 @@ import com.sksamuel.elastic4s.{ElasticError, ElasticRequest, ElasticUrlEncoder, 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)) } } diff --git a/elastic4s-core/src/test/scala/com/sksamuel/elastic4s/requests/searches/MultiSearchHandlerTest.scala b/elastic4s-core/src/test/scala/com/sksamuel/elastic4s/requests/searches/MultiSearchHandlerTest.scala new file mode 100644 index 000000000..18f2b02f3 --- /dev/null +++ b/elastic4s-core/src/test/scala/com/sksamuel/elastic4s/requests/searches/MultiSearchHandlerTest.scala @@ -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) + } +}