By Alvin Alexander. Last updated: June 24, 2016
If you want to write “async” Play Framework controller methods, I hope the following example code will help you get started. I’ll offer it here without much description today, other than to say that the list
and add
methods are written to work asynchronously by invoking Action.async
and using a Scala Future:
package controllers import play.api._ import play.api.mvc._ import play.api.data._ import play.api.data.Forms._ import play.api.data.validation.Constraints._ import views._ import models._ import scala.collection.mutable.ArrayBuffer import play.api.libs.json._ import play.api.libs.json.Json import play.api.libs.json.Json._ import java.util.Calendar object Transactions extends Controller { val transactionForm: Form[Transaction] = Form( // the names you use in this mapping (such as 'symbol') must match the names that will be // POSTed to your methods in JSON. // note: skipping `id` field // note: skipping `datetime` field mapping( // verifying here creates a field-level error; if your test returns false, the error is shown "symbol" -> nonEmptyText, "ttype" -> nonEmptyText, "price" -> bigDecimal, "quantity" -> number, "notes" -> text ) // transactionForm -> Transaction ((symbol, ttype, price, quantity, notes) => Transaction(0, symbol, ttype, price, quantity, Calendar.getInstance.getTime, notes)) // Transaction -> TransactionForm ((t: Transaction) => Some(t.symbol, t.ttype, t.price.toDouble, t.quantity, t.notes)) ) // needed to return async results import play.api.libs.concurrent.Execution.Implicits.defaultContext /** * Create a list of transactions, asynchronously. */ def list = Action.async { val transactionsAsFuture = scala.concurrent.Future{ Transaction.getAll } transactionsAsFuture.map(transactions => Ok(Json.toJson(transactions))) } /** * Delete a transaction, asynchronously. */ def delete(id: Long) = Action.async { val futureNumRowsDeleted = scala.concurrent.Future{ Transaction.delete(id) } // TODO handle the case where 'count < 1' properly futureNumRowsDeleted.map{ count => val result = Map("success" -> toJson(true), "msg" -> toJson("Transaction was deleted"), "id" -> toJson(count)) Ok(Json.toJson(result)) } } /** * The Sencha client will send me id, symbol, and companyName in a POST request. * I need to return something like this on success: * { "success" : true, "msg" : "", "id" : 100 } */ def add = Action { implicit request => transactionForm.bindFromRequest.fold( errors => { Ok(Json.toJson(Map("success" -> toJson(false), "msg" -> toJson("Boom!"), "id" -> toJson(0)))) }, transaction => { val id = Transaction.insert(transaction) id match { case Some(autoIncrementId) => val result = Map("success" -> toJson(true), "msg" -> toJson("Success!"), "id" -> toJson(autoIncrementId)) Ok(Json.toJson(result)) case None => // TODO inserts can fail; i need to handle this properly. val result = Map("success" -> toJson(true), "msg" -> toJson("Success!"), "id" -> toJson(-1)) Ok(Json.toJson(result)) } } ) } }
For more Play Framework async examples, see this link: playframework.com/documentation/2.2.x/ScalaAsync.