How to handle multipart and non multipart request together in Spray


In this blog, I will explain that how can we handle multipart and non multipart request together.

It is not necessary that we will get only one type of request either multipart or non multipart all the time. We can get either both of two. So we have to handle both type of request.

If we will handle only one type of request then if another type of request will come then we will not be able to handle that and nothing will happen.

So here, I am explaining the way to handle both type of request in spray.

We are getting the request on this URL:
http://"server IP":"Port"/email

 val emailRoutes ={
       path("email"){
            entity(as[MultipartContent]){ emailData=>

            }
       }~
       path("email"){
           entity(as[FormData]) { emailData =>

            }
       }
}

In above, first one is handling multipart request while second one is handling non multipart (application url encoded) request.

Now if we get multipart request then we should handle this request like this :

 entity(as[MultipartContent]) { emailData =>
          post {
            val dataInParts = emailData.parts.seq map {
              emailPart => (emailPart.name.get -> emailPart)
            }
            val dataInPartsMap = Map(dataInParts: _*)
            val totalAttachment = dataInPartsMap("attachment-count").entity.data.asString.toInt
            val attachmentList = for (i <- 1 to totalAttachment) yield {
              val (meta, stream, fileName) = findAttachment(dataInPartsMap, i)
              AmazonS3Communicator.upload(meta, stream, fileName)
              fileName
            }
            val informationLogMap = dataInPartsMap map {
              info => info._1 -> info._2.entity.data.asString
            }
            complete("OK")
          }
        }

Below is the method which extract attachment detail :

private def findAttachment(dataMap: Map[String, spray.http.BodyPart], attachmentCount: Int) = {
    val headerList = dataMap("attachment-" + attachmentCount).headers map (header => header.name -> header.value)
    val headerMap = Map(headerList: _*)
    val fileType = headerMap.getOrElse("Content-Type", "")
    val fileSize = headerMap.getOrElse("Content-Length", "").toLong
    val fileName = generateUUID + "_" + dataMap("attachment-" + attachmentCount).filename.get
    val stream = new ByteArrayInputStream(dataMap("attachment-" + attachmentCount).entity.data.toByteArray)
    val meta = new ObjectMetadata()
    meta.setContentLength(fileSize)
    meta.setContentType(fileType)
    (meta, stream, fileName)
  }

Below method is used for generating UID for attachments name. because we can get same name attachment more than once. So to differentiate, we prepend UID to each attachment file name.

 private def generateUUID: String = UUID.randomUUID.toString

And, if we get non multipart request (application-url-encoded) then we should handle like this :

entity(as[FormData]) { emailData =>
          post {
            val dataInParts = emailData.fields.seq map {
              data => data._1 -> data._2
            }
            val dataInPartsMap = Map(dataInParts: _*)
           complete("OK")
          }
        }

About Rishi Khandelwal

Sr. Software Consultant having more than 6 years industry experience. He has working experience in various technologies such as Scala, Java, Play, Akka, Spark, Hive, Cassandra, Akka-http, ElasticSearch, Backbone.js, html5, javascript, Less, Amazon EC2, WebRTC, SBT
This entry was posted in Agile, Akka, Scala. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s