Am trecut de la web api-uri din .Net in Scala si am o mica nelamurire despre Async, Await, Future
Folosesc Play Framework cu Slick si MySQL ca db.
Am gasit destul de multe variante prin care se poate face un insert in db (ca exemplu), dar nu reusesc sa o aleg pe cea mai buna. Stiu ca e bine ca functiile controllerului sa fie async (in documentatia Play am gasit ca toate functiile sunt predefinite async).
Incep cu cel mai simplu exemplu … stergerea unei linii din tabela Users.
Controller.scala
def delete(id: Int) = Action.async {
Future {
val res = usersRepository.delete(id)
if (res == 1) {
Ok(Json.toJson("true"))
}
else {
InternalServerError("Internal server error")
}
}
}
repository.scala :
def delete(id: Int) {
//dbUsers.filter(_.id === id).delete
Try(dbUsers.filter(_.id === id).delete) match {
case Success(response) => db.run(response)
case Failure(_) => println("An error occurred!")
}
}
In repository, unde tin interogarile, ar fi indicat sa folosesc Try sau Future? Daca folosesc Future, in controller ma obliga sa schimb utilizarea repositoriului in
Await.result(usersRepository.delete(id), Duration.Inf) / ce ar fi indicat sa returnez din repository dupa executare, un Future[String, Int, Obj] sau pur si simplu obiectul in sine, in conditia in care toate metodele controllerului vor fi async. Intre repo si controller poate aparea un serviciu (in functie de complexitatea aplicatiei), deci ar deveni si mai complicat.
Un alt lucru ce nu imi place, daca definesc actiunea async (Action.async), ma obliga sa folosesc Future { tot corpul functiei } sau la fiecare return sa folosesc Future.successful(Ok(Json.toJson(“tralalala”))) … atat de urata e scrierea in Scala? in .Net era mult mai elegant :))
si functia create() din controller, care e “cea mai complexa” de pana acum
def create = Action.async(parse.json) {
implicit request => {
Future {
User.form.bindFromRequest.fold(
formWithErrors => BadRequest(Json.toJson("Some form fields are not validated.")),
success => {
val userFromJson = Json.fromJson[User](request.body)
userFromJson match {
case JsSuccess(user: User, path: JsPath) => {
val createdUser = Await.result(usersRepository.create(user), Duration.Inf)
Created(Json.toJson(createdUser))
}
case error@JsError(_) => {
println(error)
InternalServerError(Json.toJson("Can not create user"))
}
}
}
)
}
}
}
plus repo:
def create(user: User): Future[User] = {
val insertQuery = dbUsers returning dbUsers.map(_.id) into ((x, id) => x.copy(id = id))
val query = insertQuery += user
db.run(query)
}
as fi vrut cumva sa mut toata actiunea din controller intr-un serviciu, iar aici sa ramana doar apelul serviciului, incerc sa tin controllerul cat mai simplu, functiile lui sa apeleze un serviciu ce intoarce raspunsul pentru client.
accept critici, e primul CRUD facut in Scala :)))))