2015-02-01 2 views
4

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

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) 
} 

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

ответ

2

Определите свою собственную read и write методу AdSession как это:

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

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

Другой вопрос - как передать собранные ошибки в маршрут распыления. Я хотел бы предложить вам, чтобы обернуть 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 = ??? 
} 

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

+1

Спасибо. Попробуем попробовать. Поскольку это такая распространенная вещь (проверка входных данных), я надеялся, что там могут быть хорошие шаблоны/условные обозначения/примеры, которые я могу использовать. Спасибо, что указал на Скала. Или не знал, что он существует. Я вижу, как я могу использовать [AdSession, BadRequestErrors] для достижения того, что мне нужно. Тем не менее, как небольшая коррекция, вы, вероятно, имели в виду Left вместо Lift. –

2

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

Смежные вопросы