+htt 16841 uploadedFile directive
Two new directives for accepting file uploads through multipart forms: `uploadedFile` which allows for very simple upload into a temporary file `fileUpload` which allows to simply work with the stream of bytes of an upload
This commit is contained in:
parent
35b690371f
commit
3c0877d964
10 changed files with 401 additions and 0 deletions
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* Copyright (C) 2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
package docs.http.scaladsl.server.directives
|
||||
|
||||
import java.io.File
|
||||
|
||||
import akka.http.scaladsl.model.{ MediaTypes, HttpEntity, Multipart, StatusCodes }
|
||||
import akka.stream.io.Framing
|
||||
import akka.util.ByteString
|
||||
import docs.http.scaladsl.server.RoutingSpec
|
||||
|
||||
import scala.concurrent.Future
|
||||
import scala.util.{ Success, Failure }
|
||||
|
||||
class FileUploadDirectivesExamplesSpec extends RoutingSpec {
|
||||
|
||||
override def testConfigSource = "akka.actor.default-mailbox.mailbox-type = \"akka.dispatch.UnboundedMailbox\""
|
||||
|
||||
"uploadedFile" in {
|
||||
|
||||
val route =
|
||||
uploadedFile("csv") {
|
||||
case (metadata, file) =>
|
||||
// do something with the file and file metadata ...
|
||||
file.delete()
|
||||
complete(StatusCodes.OK)
|
||||
}
|
||||
|
||||
// tests:
|
||||
val multipartForm =
|
||||
Multipart.FormData(
|
||||
Multipart.FormData.BodyPart.Strict(
|
||||
"csv",
|
||||
HttpEntity(MediaTypes.`text/plain`, "1,5,7\n11,13,17"),
|
||||
Map("filename" -> "data.csv")))
|
||||
|
||||
Post("/", multipartForm) ~> route ~> check {
|
||||
status shouldEqual StatusCodes.OK
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
"fileUpload" in {
|
||||
|
||||
// adding integers as a service ;)
|
||||
val route =
|
||||
extractRequestContext { ctx =>
|
||||
implicit val mat = ctx.materializer
|
||||
implicit val ec = ctx.executionContext
|
||||
|
||||
fileUpload("csv") {
|
||||
case (metadata, byteSource) =>
|
||||
|
||||
val sumF: Future[Int] =
|
||||
// sum the numbers as they arrive so that we can
|
||||
// accept any size of file
|
||||
byteSource.via(Framing.delimiter(ByteString("\n"), 1024))
|
||||
.mapConcat(_.utf8String.split(",").toVector)
|
||||
.map(_.toInt)
|
||||
.runFold(0) { (acc, n) => acc + n }
|
||||
|
||||
onSuccess(sumF) { sum => complete(s"Sum: $sum") }
|
||||
}
|
||||
}
|
||||
|
||||
// tests:
|
||||
val multipartForm =
|
||||
Multipart.FormData(Multipart.FormData.BodyPart.Strict(
|
||||
"csv",
|
||||
HttpEntity(MediaTypes.`text/plain`, "2,3,5\n7,11,13,17,23\n29,31,37\n"),
|
||||
Map("filename" -> "primes.csv")))
|
||||
|
||||
Post("/", multipartForm) ~> route ~> check {
|
||||
status shouldEqual StatusCodes.OK
|
||||
responseAs[String] shouldEqual "Sum: 178"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -62,6 +62,7 @@ Directive Description
|
|||
:ref:`-extractUri-` Extracts the complete request URI
|
||||
:ref:`-failWith-` Bubbles the given error up the response chain where it is dealt with by the
|
||||
closest :ref:`-handleExceptions-` directive and its ``ExceptionHandler``
|
||||
:ref:`-fileUpload-` Provides a stream of an uploaded file from a multipart request
|
||||
:ref:`-formField-` Extracts an HTTP form field from the request
|
||||
:ref:`-formFields-` Extracts a number of HTTP form field from the request
|
||||
:ref:`-get-` Rejects all non-GET requests
|
||||
|
|
@ -199,6 +200,7 @@ Directive Description
|
|||
:ref:`-setCookie-` Adds a ``Set-Cookie`` response header with the given cookies
|
||||
:ref:`-textract-` Extracts a number of values using a ``RequestContext ⇒ Tuple`` function
|
||||
:ref:`-tprovide-` Injects a given tuple of values into a directive
|
||||
:ref:`-uploadedFile-` Streams one uploaded file from a multipart request to a file on disk
|
||||
:ref:`-validate-` Checks a given condition before running its inner route
|
||||
:ref:`-withExecutionContext-` Runs its inner route with the given alternative ``ExecutionContext``
|
||||
:ref:`-withMaterializer-` Runs its inner route with the given alternative ``Materializer``
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ Directives filtering or extracting from the request
|
|||
:ref:`BasicDirectives` and :ref:`MiscDirectives`
|
||||
Directives handling request properties.
|
||||
|
||||
:ref:`FileUploadDirectives`
|
||||
Handle file uploads.
|
||||
|
||||
|
||||
.. _Response Directives:
|
||||
|
||||
|
|
@ -85,6 +88,7 @@ List of predefined directives by trait
|
|||
debugging-directives/index
|
||||
execution-directives/index
|
||||
file-and-resource-directives/index
|
||||
file-upload-directives/index
|
||||
form-field-directives/index
|
||||
future-directives/index
|
||||
header-directives/index
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
.. _-fileUpload-:
|
||||
|
||||
fileUpload
|
||||
==========
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/server/directives/FileUploadDirectives.scala
|
||||
:snippet: fileUpload
|
||||
|
||||
Description
|
||||
-----------
|
||||
Simple access to the stream of bytes for a file uploaded as a multipart form together with metadata
|
||||
about the upload as extracted value.
|
||||
|
||||
If there is no field with the given name the request will be rejected, if there are multiple file parts
|
||||
with the same name, the first one will be used and the subsequent ones ignored.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/FileUploadDirectivesExamplesSpec.scala
|
||||
:snippet: fileUpload
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
.. _FileUploadDirectives:
|
||||
|
||||
FileUploadDirectives
|
||||
====================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
uploadedFile
|
||||
fileUpload
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
.. _-uploadedFile-:
|
||||
|
||||
uploadedFile
|
||||
============
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/server/directives/FileUploadDirectives.scala
|
||||
:snippet: uploadedFile
|
||||
|
||||
Description
|
||||
-----------
|
||||
Streams the contents of a file uploaded as a multipart form into a temporary file on disk and provides the file and
|
||||
metadata about the upload as extracted value.
|
||||
|
||||
If there is an error writing to disk the request will be failed with the thrown exception, if there is no field
|
||||
with the given name the request will be rejected, if there are multiple file parts with the same name, the first
|
||||
one will be used and the subsequent ones ignored.
|
||||
|
||||
.. note::
|
||||
This directive will stream contents of the request into a file, however one can not start processing these
|
||||
until the file has been written completely. For streaming APIs it is preferred to use the :ref:`-fileUpload-`
|
||||
directive, as it allows for streaming handling of the incoming data bytes.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/FileUploadDirectivesExamplesSpec.scala
|
||||
:snippet: uploadedFile
|
||||
|
|
@ -77,6 +77,7 @@ in the :ref:`exception-handling-scala` section of the documtnation. You can use
|
|||
|
||||
File uploads
|
||||
^^^^^^^^^^^^
|
||||
For high level directives to handle uploads see the :ref:`FileUploadDirectives`.
|
||||
|
||||
Handling a simple file upload from for example a browser form with a `file` input can be done
|
||||
by accepting a `Multipart.FormData` entity, note that the body parts are `Source` rather than
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue