File upload using akka-http in Scala


Lets begin with some introduction of Akka-http first.

Akka HTTP is a layer to expose Actors to the web via HTTP and to enable them to consume HTTP services as a client. It is not an HTTP framework, it is an Actor-based toolkit for interacting with web services and clients. This toolkit is structured into several layers:

  • akka-http-core: A complete implementation of the HTTP standard, both as client and server.
  • akka-http: A convenient and powerful routing DSL for expressing web services.
  • akka-http-testkit: A test harness and set of utilities for verifying your web service implementations.

For more information, see here.

Now its time to go into some code.

To use akka-http, we need to add library in our application.  So to do the same, add following dependencies in build.sbt file.:


"com.typesafe.akka" %% "akka-stream-experimental" % "2.0.2",
"com.typesafe.akka" %% "akka-http-core-experimental" % "2.0.2",
"com.typesafe.akka" %% "akka-http-experimental" % "2.0.2"

Now we will write a route to which we can send our file upload request :


package com.rishi

import java.io.FileOutputStream
import java.util.UUID

import akka.actor.ActorSystem
import akka.http.scaladsl.model.{HttpResponse, Multipart, StatusCodes}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import akka.stream.ActorMaterializer
import akka.util.ByteString

trait FileUpload {

  implicit val system = ActorSystem()
  implicit val executor = system.dispatcher
  implicit val materializer = ActorMaterializer()

  /**
   * Route for uploading file
   */
  def uploadFile: Route = {
    path("user" / "upload" / "file") {
      (post & entity(as[Multipart.FormData])) { fileData =>
          complete {
              val fileName = UUID.randomUUID().toString
              val temp = System.getProperty("java.io.tmpdir")
               val filePath = temp + "/" + fileName
              processFile(filePath,fileData).map { fileSize =>
              HttpResponse(StatusCodes.OK, entity = s"File successfully uploaded. Fil size is $fileSize")
              }.recover {
               case ex: Exception => HttpResponse(StatusCodes.InternalServerError, entity = "Error in file uploading")
               }
          }
      }
    }
  }

  private def processFile(filePath: String, fileData: Multipart.FormData) = {
    val fileOutput = new FileOutputStream(filePath)
    fileData.parts.mapAsync(1) { bodyPart ⇒
      def writeFileOnLocal(array: Array[Byte], byteString: ByteString): Array[Byte] = {
        val byteArray: Array[Byte] = byteString.toArray
        fileOutput.write(byteArray)
        array ++ byteArray
      }
      bodyPart.entity.dataBytes.runFold(Array[Byte]())(writeFileOnLocal)
    }.runFold(0)(_ + _.length)
  }

  val routes = uploadFile
}

Here, what we have done is, as route will get file upload request, it will take the file data as multipart and will create a file at our local machine in system’s temp folder.

That’s it. Hope you enjoyed. Happy Blogging. !!!

About Rishi Khandelwal

Sr. Software Engineer having more than 5 years industry experience. He has working experience in various technologies such as Scala, Java, Play, Akka, Lift Web, Spark, ElasticSearch, Backbone.js, html5, javascript, Less, Amazon EC2, WebRTC, SBT
This entry was posted in Akka, Future, knoldus, Scala. Bookmark the permalink.

13 Responses to File upload using akka-http in Scala

  1. Pingback: File upload using akka-http in Scala | Arpit Suthar

  2. Hi, I am getting an error in the function processFile() – not enough arguments for method runFold: (implicit materializer: akka.stream.Materializer)scala.concurrent.Future[Array[Byte]]. Unspecified value parameter materializer. I tried adding these:

    import akka.actor.ActorSystem
    import akka.stream.ActorMaterializer
    implicit val system = ActorSystem(“Sys”)
    implicit val materializer = ActorMaterializer()

    Then I started getting error in the uploadFile function in line : processFile(filePath, fileData).map { fileSize =>

    ◾Cannot find an implicit ExecutionContext. You might pass an (implicit ec: ExecutionContext) parameter to your method or import scala.concurrent.ExecutionContext.Implicits.global

    Can you pls help me resolve this, so that the async nature is not lost

    • Hi Anand. Thanks for pointing me the error.

      I have updated the blog. I missed to include some implicit variables.
      Now please give it a try one more time and let me know if you get any error.

  3. Hello Rishi,
    One other thing I noticed is that, when I try to upload a file of size 150 MB, the POST request is failing after around 8-9 seconds. Any idea how to fix it?

  4. A.G. says:

    Hello Anand,
    150MB issue may be related to akka-http config. Default incoming request size is 8MB. Have you tried increasing akka.http.server.parsing.max-content-length ?
    http://doc.akka.io/docs/akka-stream-and-http-experimental/2.0.2/scala/http/configuration.html

  5. avis says:

    Looks good, How do we get form-data inside multipart?

  6. Pingback: Test cases for file upload using akka-http in Scala | Knoldus

  7. Pingback: A basic application to handle multipart form data using akka-http with test cases in Scala | Knoldus

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