我有ServerA公开客户端的API方法,如下所示:
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"))
}
}
所以,我有一个客户端请求的case类,如果我不能从请求体中提取它,那么我返回一个带有消息的BadRequest
,否则我调用内部apiService
来执行对此请求采取一些行动。
doSomething
执行对ServerB的API调用,可以返回3个可能的响应:
doSomething
看起来像这样:
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
}
}
}
现在我有两个问题:
200
返回时没有正文且400有正文,我不知道应该是doSomething
methodExposed
中正确地将响应返回给客户?答案 0 :(得分:1)
我会做这样的事情:
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 :(得分:0)
如果400是常见的预期错误,我认为类型Future[Either[Your400CaseClass, Unit]]
是有意义的。关于methodExposed
如何将结果返回给客户端取决于您的业务逻辑:
如果doSomething
返回500(或更常见的是任何意外的http代码),则应抛出异常(使用Future.failed)。
(最后,我希望你没有使用500来传递'正常'错误,如验证/身份验证错误.5xx代码只应用于异常和不可恢复的错误。我知道的大多数http客户端会立即抛出异常遇到5xx,这意味着用户将无法处理它)