Home > OS >  How to unmarshall akka http request entity as array of strings?
How to unmarshall akka http request entity as array of strings?

Time:12-30

I am trying to unmarshall a post request payload as array of strings, but it's failing with 400 bad request with the error:

The request content was malformed: Expected String as JsString, but got {"application":{"applicationRevision":{"string":"27904"},"applicationVersion":"india","id":"132231","name":"appTest"},"guest":{"session":"12bvg","systemTime":"2021-08-24T21:19:13.282Z","visitorId":"abc"}}

Body of the post request:

[{"application":{"applicationRevision":{"string":"27904"},"applicationVersion":"india","id":"132231","name":"appTest"},"guest":{"session":"12bvg","systemTime":"2021-08-24T21:19:13.282Z","visitorId":"abc"}}]

Below is the code:

def genericEventRoute: Route =
    path(basePath / version / "event" / "generic") {
      concat(
        post {
          entity(as[Array[String]]) { inputs =>
            extractClientIP { ip =>
              val ipAddress = ip.toOption.map(_.getHostAddress).getOrElse("unknown")
              system.log.info(s"ipAddress : $ipAddress")
              val operationPerformed: Future[IncomingIngest.Response] = incomingIngest.ask(IncomingIngest.ConsumeGenericEvent(inputs, ipAddress, _))
              onSuccess(operationPerformed) {
                case IncomingIngest.OK(message) => complete(StatusCodes.Created, List(`Content-Type`(`application/json`)), message)
                case IncomingIngest.KO(error) => complete(StatusCodes.BadRequest, error)
              }
            }
          }
        }
      )
    }

How can I unmarshall into array of strings!! This is working if I send a String in the request by omitting [] and using entity(as[String]) in the route. But, the payload I am supposed to get will be of array of strings. There is way to use case class to unmarshall the payload but in order to do that, all the fields inside the json have to be mapped which I don't want. The route should handle generic payload with array of strings. Can you please suggest a way to do so!

CodePudding user response:

The incoming input is a JsArray, so will have to convert that to scala Vector/List of Strings and then process accordingly. Below is the code for that:

def genericEventRoute: Route =
    path(basePath / version / "event" / "generic") {
      concat(
        post {
          entity(as[JsArray]) { inputs =>
            extractClientIP { ip =>
              val ipAddress = ip.toOption.map(_.getHostAddress).getOrElse("unknown")
              system.log.info(s"ipAddress : $ipAddress")
              val arrInput = inputs.elements.map(ele => ele.toString())
              val operationPerformed: Future[IncomingIngest.Response] = incomingIngest.ask(IncomingIngest.ConsumeGenericEvent(arrInput, ipAddress, _))
              onSuccess(operationPerformed) {
                case IncomingIngest.OK(message) => complete(StatusCodes.Created, List(`Content-Type`(`application/json`)), message)
                case IncomingIngest.KO(error) => complete(StatusCodes.BadRequest, error)
              }
            }
          }
        }
      )
    }

Remember that arrInput will be of type Vector[String]. Though the best way would be to create a case class and parse the json directly into that as mentioned by Tim in the comment. But, for those use cases where incoming message does not follow any specific format, it might lead to parsing error. In this way, we can accept any incoming messages and push to downstream where the payload can be validated.

  • Related