2016-05-13 1 views
0

Voici ma toujours plus validationRejectionHandler pour mon projet de pulvérisation:Spray Rejection Handling Crazy ... ou suis-je?

implicit def validationRejectionHandler = RejectionHandler { 
    case ValidationRejection(errMsg,_) :: _ => 
     logger.info(s"received validation error: $errMsg") 
     complete(StatusCodes.Unauthorized,errMsg) 
    case MalformedQueryParamRejection(parameterName, errorMsg, cause) :: _ => 
     logger.debug(s"received MalformedQueryParamRejection error: $errorMsg") 
     complete(BadRequest -> GenericMessageObj(s"The query parameter $parameterName was malformed: $errorMsg")) 
    case spray.routing.AuthorizationFailedRejection :: _ => 
     //todo - this string shouldn't be here 
     logger.info("received authentication error") 
     complete(StatusCodes.Unauthorized, "User is not authorized to this resource") 
    case MalformedRequestContentRejection(msg, causeOpt) :: _ => 
     complete { 
     causeOpt.map { cause => 
      cause match { 
      case e: InvalidFormatException => 
       val fieldNameMatcher = """\["(.+)"\]""".r.unanchored 
       val fieldTypeMatcher = """(\w+)$""".r.unanchored 
       e.getPath.toString match { 
       case fieldNameMatcher(fieldName) => 
        e.getTargetType.toString match { 
        case fieldTypeMatcher(fieldType) => 
         val fieldTypeLowerCase = fieldType.toLowerCase() 
         BadRequest -> GenericMessageObj(s"""Invalid data: "${fieldName}" must be a ${fieldTypeLowerCase} value, but received ${e.getValue}""") 
        case _ => 
         BadRequest -> GenericMessageObj(s"""${e.getValue} is an improper type for field "${fieldName}""") 
        } 
       case _ => 
        logger.debug(s"Failed pattern match: ${e.getPath.toString}") 
        BadRequest -> GenericMessageObj("Invalid payload format") 
      } 

      case e: UnrecognizedPropertyException => BadRequest -> GenericMessageObj(s"Unrecognized property: ${e.getPropertyName}") 

      case e: JsonMappingException => 
       if(cause.getCause == null || cause.getCause.getMessage == null){ 
       val deserializationMsgMatcher = """Can not deserialize instance of scala\.collection\.(Seq) out of (VALUE_NUMBER_INT) [\s\S]+"(name)":[+-]?\d\};[\s\S]+\["(\3)"\].+""".r.unanchored 
       cause.getMessage match { 
        case deserializationMsgMatcher(expected, actual, fieldName, _) => 
        logger.debug(s"Desrializaiton error at $fieldName: Found $actual instead of $expected") 
        BadRequest -> GenericMessageObj(s"Invalid format for $fieldName") 
        case _ => 
        BadRequest -> GenericMessageObj(s"${cause.getMessage}") 
        } 
       } else if (!cause.getCause.getMessage.isEmpty) { 
       BadRequest -> GenericMessageObj(cause.getCause.getMessage) 
       } else { 
       BadRequest -> GenericMessageObj(s"Invalid data format") 
       } 
      case _ => BadRequest -> GenericMessageObj(s"An unknown error occurred.") 
      } 
     } 
     } 
    case spray.routing.MissingHeaderRejection(headerName) :: _ => 
     complete(BadRequest -> GenericMessageObj("%s header is missing.".format(headerName))) 
    } 
} 

Il me semble fou que ce peu alambiquée code - avec regexes à déchiffrer différents types d'erreurs - est la façon de gérer les rejets dans Pulvériser pour ne pas renvoyer des messages laids aux clients API:

{ "message": "Valeur manquante de la propriété de créateur requise" (index 2) \ n at [Source: {\ n \ " source \ ": \" k \ ", \ n \" valeurs \ ": [\ n {\ n \" dt \ ": \" 2015-10-15T16: 27: 42.014Z \ ", \ n \" id \ ": \" 0022A3000004E6E1 \ ", \ n \ n \" attribut \ ": \" a \ ", \ n \" _ id \ ": \" 45809haoua \ ", \ n \" __ id \ ": \" a2p49t7ya4wop9h \ ", \ n \" ___ id \ ": \" q2ph84yhtq4pthqg \ "\ n}] \ n}; ligne: 12, colonne: 9] (via la chaîne de référence: io.keenhome.device.models.DatumList [\ "values ​​\"] -> com.fasterxml.jackson.module.scala.deser.BuilderWrapper [0]) " }

Comment puis-je gérer ces messages d'erreur (par exemple le retour non-ordures aux clients API) sans avoir à faire une expression régulière sur les chaînes qui sont susceptibles de changer?

+0

Votre question est trop générale. Était-ce vous qui avez écrit le code ci-dessus? Si oui, vous pouvez le réécrire de manière plus simple. Sinon, je recommande de poser une question plus spécifique. – expert

+0

Mis à jour pour poser une question plus spécifique – threejeez

Répondre

0

Ah, je vois. ces messages fous sont générés par . Jackson (et non par pulvérisation) vous avez des options couple:.

1) Poignée JSONObjectException dans handleExceptions directive

2) Ou saisissez et transformez JSONObjectException dans votre classe d'exception avant qu'elle n'atteigne le routage. Ensuite, je gérerais la réponse avec un gestionnaire d'exception personnalisé.

implicit def myExceptionHandler = 
    ExceptionHandler { 
    case ex: ExceptionWithUser => ctx => { 
     val user = ex.user 
     val cause = ex.getCause 
     logger.error(s"${cause.getClass.getSimpleName} for ${ex.user.name} [${ex.user.id}]", cause) 
     ctx.complete(StatusCodes.InternalServerError, ErrorResponse(ex.code, ex)) 
    } 
    case ex: Throwable => ctx => 
     logger.warning("Request {} could not be handled normally", ctx.request) 
     ctx.complete(StatusCodes.InternalServerError, ErrorResponse(StatusCodes.InternalServerError.intValue, ex)) 
    } 

et pour refus j'utiliser gestionnaire de rejet personnalisé qui convertit le texte par défaut de refus AKKA-http à la réponse JSON que les clients attendent de l'API (je peux le montrer si vous le souhaitez).