Upload file Scala Spray - scala

Looking to create functionality to upload a file using multipart/form-data. However I cannot grasp how to change the MultipartFormData and store it in the file system. Below is what I have so far.
trait Service extends HttpService {
private final lazy val fileWorker = actorRefFactory.actorOf(Props[FileServicesActor])
implicit def executionContext = actorRefFactory.dispatcher
val demoRoute: Route = {
path("file") {
post {
respondWithMediaType(`application/json`) {
entity(as[MultipartFormData]) { formData =>
uploadFile(formData)
}
}
}
}
}
private def uploadFile(data: MultipartFormData)= {
val response = (fileWorker ? UploadFile(data)).mapTo[Any].map { case t: Success => t
case e: Error => Error.outputError(e)
case _ => Failure(_)
}.recover { case e: Exception => Failure(e)
}
complete(response)
}
}
The function resolves to this
def uploadFile(data: MultipartFormData) = {
val file = data.get("file")
//not sure what to do with data here...
}

Related

Test With Server Example Code Not Working

I am not understanding something about this example in Play 2.7 documentation
class ExampleSpec extends PlaySpec with GuiceOneServerPerSuite {
// Override app if you need an Application with other than
// default parameters.
override def fakeApplication(): Application = {
GuiceApplicationBuilder()
.appRoutes(app => {
case ("GET", "/") => app.injector.instanceOf(classOf[DefaultActionBuilder]) { Ok("ok") }
}).build()
}
"test server logic" in {
val wsClient = app.injector.instanceOf[WSClient]
val myPublicAddress = s"localhost:$port"
val testPaymentGatewayURL = s"http://$myPublicAddress"
// The test payment gateway requires a callback to this server before it returns a result...
val callbackURL = s"http://$myPublicAddress/callback"
// await is from play.api.test.FutureAwaits
val response = await(wsClient.url(testPaymentGatewayURL).addQueryStringParameters("callbackURL" -> callbackURL).get())
response.status mustBe OK
}
}
The problem is this code:
.appRoutes(app => {
case ("GET", "/") => app.injector.instanceOf(classOf[DefaultActionBuilder]) { Ok("ok") }
I get message that it expecting Application => PartialFunction[(String, String), Handler]
What is Handler? Is my controller?
This is down to lack of type inference I assume.
If you add the required type annotation (i.e. add : PartialFunction[(String, String), Handler]) you should be able to compile:
override def fakeApplication(): Application = {
GuiceApplicationBuilder()
.appRoutes(app => {
case ("GET", "/") => app.injector.instanceOf(classOf[DefaultActionBuilder]) { x => play.api.mvc.Results.Forbidden }
}: PartialFunction[(String, String), Handler]
).build()
}

Unable to recover exception in Future in Scala

The following Scala code uses cats EitherT to wrap results in a Future[Either[ServiceError, T]]:
package com.example
import com.example.AsyncResult.AsyncResult
import cats.implicits._
import scala.concurrent.ExecutionContext.Implicits.global
class ExternalService {
def doAction(): AsyncResult[Int] = {
AsyncResult.success(2)
}
def doException(): AsyncResult[Int] = {
println("do exception")
throw new NullPointerException("run time exception")
}
}
class ExceptionExample {
private val service = new ExternalService()
def callService(): AsyncResult[Int] = {
println("start callService")
val result = for {
num <- service.doException()
} yield num
result.recoverWith {
case ex: Throwable =>
println("recovered exception")
AsyncResult.success(99)
}
}
}
object ExceptionExample extends App {
private val me = new ExceptionExample()
private val result = me.callService()
result.value.map {
case Right(value) => println(value)
case Left(error) => println(error)
}
}
AsyncResult.scala contains:
package com.example
import cats.data.EitherT
import cats.implicits._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
object AsyncResult {
type AsyncResult[T] = EitherT[Future, ServiceError, T]
def apply[T](fe: => Future[Either[ServiceError, T]]): AsyncResult[T] = EitherT(fe)
def apply[T](either: Either[ServiceError, T]): AsyncResult[T] = EitherT.fromEither[Future](either)
def success[T](res: => T): AsyncResult[T] = EitherT.rightT[Future, ServiceError](res)
def error[T](error: ServiceError): AsyncResult[T] = EitherT.leftT[Future, T](error)
def futureSuccess[T](fres: => Future[T]): AsyncResult[T] = AsyncResult.apply(fres.map(res => Right(res)))
def expectTrue(cond: => Boolean, err: => ServiceError): AsyncResult[Boolean] = EitherT.cond[Future](cond, true, err)
def expectFalse(cond: => Boolean, err: => ServiceError): AsyncResult[Boolean] = EitherT.cond[Future](cond, false, err)
}
ServiceError.scala contains:
package com.example
sealed trait ServiceError {
val detail: String
}
In ExceptionExample, if it call service.doAction() it prints 2 as expected, but if it call service.doException() it throws an exception, but I expected it to print "recovered exception" and "99".
How do I recover from the exception correctly?
That is because doException is throwing exception inline. If you want to use Either, you have to return Future(Left(exception)) rather than throwing it.
I think, you are kinda overthinking this. It does not look like you need Either here ... or cats for that matter.
Why not do something simple, like this:
class ExternalService {
def doAction(): Future[Int] = Future.successful(2)
def doException(): AsyncResult[Int] = {
println("do exception")
Future.failed(NullPointerException("run time exception"))
// alternatively: Future { throw new NullPointerExceptioN() }
}
class ExceptionExample {
private val service = new ExternalService()
def callService(): AsyncResult[Int] = {
println("start callService")
val result = for {
num <- service.doException()
} yield num
// Note: the aboive is equivalent to just
// val result = service.doException
// You can write it as a chain without even needing a variable:
// service.doException.recover { ... }
result.recover { case ex: Throwable =>
println("recovered exception")
Future.successful(99)
}
}
I tend to agree that it seems a bit convoluted, but for the sake of the exercise, I believe there are a couple of things that don't quite click.
The first one is the fact that you are throwing the Exception instead of capturing it as part of the semantics of Future. ie. You should change your method doException from:
def doException(): AsyncResult[Int] = {
println("do exception")
throw new NullPointerException("run time exception")
}
To:
def doException(): AsyncResult[Int] = {
println("do exception")
AsyncResult(Future.failed(new NullPointerException("run time exception")))
}
The second bit that is not quite right, would be the recovery of the Exception. When you call recoverWith on an EitherT, you're defining a partial function from the Left of the EitherT to another EitherT. In your case, that'd be:
ServiceError => AsyncResult[Int]
If what you want is to recover the failed future, I think you'll need to explicitly recover on it. Something like:
AsyncResult {
result.value.recover {
case _: Throwable => {
println("recovered exception")
Right(99)
}
}
}
If you really want to use recoverWith, then you could write this instead:
AsyncResult {
result.value.recoverWith {
case _: Throwable =>
println("recovered exception")
Future.successful(Right(99))
}
}

Scala write collection of objects to HttpResponse

I'm scala beginner and for now I'm trying to build a basic play/slick app (sort of user database).
It seems I've been able to build up all the stuff but data transferring to the front-end.
Here is what I have:
UserDAO.scala
class UserDao #Inject()(protected val dbConfigProvider: DatabaseConfigProvider) extends BaseDao {
import driver.api._
def entities = TableQuery[UsersTable]
def all(): Future[Seq[User]] = {
db.run(entities.result)
}
class UsersTable(tag: Tag) extends BaseTable(tag, "USER") {
def email = column[String]("email")
def password = column[String]("password")
def * = (id, email, password) <> (User.tupled, User.unapply)
}
}
Application.scala
Application #Inject()(userDAO: UserDao) extends Controller {
def users = Action.async {
val userList = userDAO.all()
userList
.map { list => Ok(list.map(elem => Json.toJson(elem : UserDto))) }
.recover { case _ => InternalServerError }
}
}
UserDTO.scala
case class UserDto(id: Long, login: String)
object UserDto {
implicit val userWriter = Json.writes[UserDto]
implicit def from(user: User): UserDto = UserDto(user.id, user.login)
}
What I don't understand is why compiler complains about .map { list => Ok(list.map(elem => Json.toJson(elem : UserDto))) } in Application.scala. It seems that I provided everything required for conversion to json. Could please, anybody, show what I'm doing wrong?
Replace Ok(list.map(elem => Json.toJson(elem : UserDto))) with Json.toJson(list: Seq[UserDto])
Application #Inject()(userDAO: UserDao) extends Controller {
def users = Action.async {
val userList = userDAO.all()
userList
.map { list => Ok(Json.toJson(list: Seq[UserDto])) }
.recover { case _ => InternalServerError }
}
}

Scala Generics : Cannot write an instance of T to HTTP response. Try to define a Writeable[T]

Following code when written using generic give a compilation error.
Without Generic
def getData(id: String) = Action.async {
val items = getItems(id)
sendResult(items)
}
private def sendResult(result: Future[Any]) = {
result.map {
items => {
try {
val itemStr = items.asInstanceOf[String]
Ok(itemStr)
} catch {
case t: ClassCastException => InternalServerError(s"Casting Exception while processing output $t")
}
}
}.recover {
case t:TimeoutException => InternalServerError("Api Timed out")
case t: Throwable => InternalServerError(s"Exception in the api $t")
}
}
With Generic
def getData(id: String) = Action.async {
val items = getItems(id)
sendResult[String](items)
}
private def sendResult[T](result: Future[Any]) = {
result.map {
items => {
try {
val itemStr = items.asInstanceOf[T]
Ok(itemStr)
} catch {
case t: ClassCastException => InternalServerError(s"Casting Exception while processing output $t")
}
}
}.recover {
case t:TimeoutException => InternalServerError("Api Timed out")
case t: Throwable => InternalServerError(s"Exception in the api $t")
}
}
The code is part of play app's contorller method. First one works fine. Second one gives following compilation error
Cannot write an instance of T to HTTP response. Try to define a
Writeable[T] [error] Ok(itemStr) [error]
Using Any with a generic function doesn't make much sense.
private def sendResult[T](result: Future[Any])
// Should better be
private def sendResult[T](result: Future[T])
// ... also remove the unsafe cast
Then this T needs to be provided an instance of Writeable, so it can be written a Array[Byte] over network.
// Either ...
private def sendResult[T: Writeable](result: Future[T])
// ... or ...
private def sendResult[T](result: Future[T])(implicit w: Writeable[T])
The Ok(...) is calling the method apply[C](content: C)(implicit writeable: Writeable[C]): Result on Status class. You need to have an implicit value for Writeable[T] in scope.
As a side note, rather than using Future[Any], you may as well use Future[T] and remove the cast. Also you can use Writes for JSON serialization.
private def sendResult[T](result: Future[T])(implicit writeable: Writes[T]) = {
result.map {
items => {
Ok(Json.toJson(items))
}
}.recover {
case t:TimeoutException => InternalServerError("Api Timed out")
case t: Throwable => InternalServerError(s"Exception in the api $t")
}
}

Akka actors always times out waiting for future

I have the following actor as defined below meant to "login" a user.
object AuthenticationActor {
def props = Props[AuthenticationActor]
case class LoginUser(id: UUID)
}
class AuthenticationActor #Inject()(cache: CacheApi, userService: UserService) extends Actor{
import AuthenticationActor._
def receive = {
case LoginEmployee(id: UUID) => {
userService.getUserById(id).foreach {
case Some(e) => {
println("Logged user in")
val sessionId = UUID.randomUUID()
cache.set(sessionId.toString, e)
sender() ! Some(e, sessionId)
}
case None => println("No user was found")
}
}
}
}
Note: userService.getUserById returns a Future[Option[User]]
And the following very simplistic API cal to it
class EmployeeController #Inject()(#Named("authentication-actor") authActor: ActorRef)(implicit ec: ExecutionContext) extends Controller {
override implicit val timeout: Timeout = 5.seconds
def login(id: UUID) = Action.async { implicit request =>
(authActor ? LoginUser(id)).mapTo[Option[(User, UUID)]].map {
case Some(authInfo) => Ok("Authenticated").withSession(request.session + ("auth" -> authInfo._2.toString))
case None => Forbidden("Not Authenticated")
}
}
}
Both println calls will execute, but login call will always fail saying that the ask has time out. Any suggestions?
When you do such thing (accessing sender within Futures callback) you need to store sender in a val in outter scope when you receive request because it is very likely change before Future completes.
def receive = {
case LoginEmployee(id: UUID) => {
val recipient = sender
userService.getUserById(id).foreach {
case Some(e) => {
...
recipient ! Some(e, sessionId)
}
...
}
}
}
You also never send a result when user wasn't found.
What you actually should do here is pipe the Future result to the sender
def receive = {
case LoginEmployee(id: UUID) => {
userService.getUserById(id) map { _.map { e =>
val sessionId = UUID.randomUUID()
cache.set(sessionId.toString, e)
(e, sessionId)
}
} pipeTo sender
}
}
or with prints
def receive = {
case LoginEmployee(id: UUID) => {
userService.getUserById(id) map {
case Some(e) =>
println("logged user in")
val sessionId = UUID.randomUUID()
cache.set(sessionId.toString, e)
Some(e, sessionId)
case None =>
println("user not found")
None
} pipeTo sender
}
}