Scala, Akka, Spray: как проверить данные json перед обработкой?

Я могу обработать этот json, когда все входные данные действительны, то есть с действительными ключами (включая регистр) и значениями. Следующим шагом является проверка ключей и возврат 400 (неверный запрос), если ключи или значения недействительны. Каков хороший способ добавить эту проверку?

Вызов API

POST http://localhost:8080/api/v1/adsession
Content-Type: application/json
body {
  "sessionId": "abcd123123123",
  "serviceGroup": "1234",
  "targetCode": {"zipcodes":"30096,30188","code2":"value2"}
}

Обработчик маршрута

class AdSessionRoutes(services: Services)(implicit ec: ExecutionContext, log: LoggingContext) extends ApiRoute(services) {

  implicit val timeout = Timeout(10 seconds)

  val postSession = pathPrefix("adsession") & pathEnd & post

  val route: Route = {
    withService("adSession") { service =>

      postSession {
        entity(as[AdSession]) { adSession =>
          log.info(s"Processing POST ${adSession}")
          val future = (service ? CreateAdSession(adSession)).mapTo[AdSession]

          onComplete(future) {
            case Success(result) =>
              complete(StatusCodes.Created, result)

            case Failure(e) =>
              log.error(s"Error: ${e.toString}")
              complete(StatusCodes.InternalServerError, Message(ApiMessages.UnknownException))
          }
        }
      }
    }
  }
}

Объект модели

case class AdSession(
  sessionId: String,
  serviceGroup: String,
  targetCodes: Map[String,String],
  id: Option[String] = None)

object AdSessionJsonProtocol extends DefaultJsonProtocol {
  implicit val adSessionFormat = jsonFormat4(AdSession)
}

entity(as[AdSession]) сопоставляет ключи с полями класса case, но я не знаю, как отловить эти ошибки. Я хотел бы зафиксировать эти ошибки, а также добавить дополнительные проверки и вернуть 400 с допустимым ответом об ошибке json.


person Srini K    schedule 01.02.2015    source источник


Ответы (2)


Я знаю, что это может быть немного поздно, но начиная с akka-http-2.4.6 вы можете поместить логику проверки в класс case. Ознакомьтесь с этим для получения информации о том, как это сделать.

person zaxme    schedule 28.05.2016

Определите свои собственные методы read и write для AdSession следующим образом:

object AdSessionJsonProtocol {
    implicit object adSessionJsonFormat extends RootJsonFormat[AdSession] {
        override def read(json: JsValue): AdSession = ???
        override def write(obj: AdSession): JsValue = ???
    }
}

Внутри функции read вы можете выполнить дополнительную проверку.

Другой вопрос, как передать собранные ошибки в маршрут Spray. Я хотел бы предложить вам обернуть AdSession в Either[String, AdSession], например:

postSession {
        entity(as[Either[String, AdSession]]) { adSession =>

Итак, теперь ваш adSessionJsonFormat будет выглядеть так:

implicit object adSessionJsonFormat extends RootJsonFormat[Either[String, AdSession]] {

    override def read(json: JsValue): Either[String, AdSession] = {
      // json.asJsObject.fields access fields, perform checks
      // if everything is OK return Right(AdSession(...))
      // otherwise return Lift("Error Message")
    }

    override def write(obj: Either[String, AdSession]): JsValue = ???
}

Но я думаю, что это можно решить более элегантным способом, используя некоторую неявную магию.

person Artsiom Miklushou    schedule 02.02.2015
comment
Спасибо. Попробую. Поскольку это такая обычная вещь (проверка входных данных), я надеялся, что должны быть какие-то хорошие шаблоны/соглашения/примеры, которыми я могу воспользоваться. Спасибо, что указали на Scala. Либо не знал, что он существует. Я вижу, как я могу использовать Both[AdSession, BadRequestErrors] для достижения того, что мне нужно. В качестве небольшой поправки, вы, вероятно, имели в виду «Влево» вместо «Подъем». - person Srini K; 02.02.2015