Recommendations for handling an HTTP response using scala

I have ServerA that provides an API method for a client that looks like this:

def methodExposed()= Action.async(json) { req =>

    val reqAsModel = request.body.extractOpt[ClientRequestModel]

    reqAsModel match {
      case Some(clientRequest) =>
        myApiService
          .doSomething(clientRequest.someList)
          .map(res => ???)
      case None =>
        Future.successful(BadRequest("could not extract request"))
    }
  }

So, I have a case class for a client request, and if I cannot extract it from the request body, then I return a message BadRequestwith a message, and otherwise I call an internal apiServicerequest to perform some actions with this.

doSomething makes a call to the ServerB API, which can return 3 possible responses:

  • State 200
  • 400 status with body, which I need to extract into the case class
  • State 500

doSomething as follows:

def doSomething(list: List[String]) = {
    wSClient.url(url).withHeaders(("Content-Type", "application/json")).post(write(list)).map { response =>
      response.status match {
        case Status.BAD_REQUEST =>
          parse(response.body).extract[ServiceBResponse]
        case Status.INTERNAL_SERVER_ERROR =>
          val ex = new RuntimeException(s"ServiceB Failed with status: ${response.status} body: ${response.body}")
          throw ex
      }
    }
  }

Now I have two problems:

  • Since it 200returns without a body and 400 has a body, I do not know what the return type should bedoSomething
  • methodExposed?
+4
2

400 , , Future[Either[Your400CaseClass, Unit]] . , methodExposed , -:

  • 400, ? Exposed 500 , doSomething 400
  • . - case , , http-.

( Future.failed), doSomething 500 (, , http-).

(, , 500 "" , , /. 5xx . HTTP-, , 5xx, , )

0

- :

case class ServiceBResponse(status: Int, body: Option[String] = None)

doSomething :

def doSomething(list: List[String]) = {
  wSClient.url(url).withHeaders(("Content-Type", "application/json")).post(write(list)).map { response =>
    response.status match {
      case Status.OK =>
        ServiceBResponse(response.status)
      case Status.BAD_REQUEST =>
        ServiceBResponse(response.status, Option(response.body))
      case Status.INTERNAL_SERVER_ERROR =>
        val message = s"ServiceB Failed with status: ${response.status} body: ${response.body}"
        ServiceBResponse(response.status, Option(message))
    }
  }
}

, :

def methodExposed() = Action.async(json) { req =>

  val reqAsModel = request.body.extractOpt[ClientRequestModel]

  reqAsModel match {
    case Some(clientRequest) =>
      myApiService
        .doSomething(clientRequest.someList)
        .map(serviceBResponse => Status(serviceBResponse.status)(serviceBResponse.getOrElse("")))
    case None =>
      Future.successful(BadRequest("could not extract request"))
  }
}

WSResponse:

def doSomething(list: List[String]) = {
    wSClient
        .url(url)
        .withHeaders(("Content-Type", "application/json"))
        .post(write(list))
}

:

def methodExposed() = Action.async(json) { req =>

  val reqAsModel = request.body.extractOpt[ClientRequestModel]

  reqAsModel match {
    case Some(clientRequest) =>
      myApiService
        .doSomething(clientRequest.someList)
        .map(wsResponse => Status(wsResponse.status)(wsResponse.body))
    case None =>
      Future.successful(BadRequest("could not extract request"))
  }
}
+1

Source: https://habr.com/ru/post/1673484/


All Articles