UserServiceImpl.createUser
Here’s the code for UserServiceImpl.createUser
:
def createUser(info: UserInfo): Future[UserInfo] = {
{
for {
created <- repo.create(info.toUser)
} yield {
UserInfo(created.get)
}
} recover {
case e: DuplicateKeyValException[_, _] => handleDuplicateKeyVal(e, info)
}
}
The heart of the method is the call to repo.create
, inside the
for comprehension. repo.create
returns a
Future[PState[User]]
. The future is there because we want to treat
the underlying database call in an asynchronous fashion. The User
is
further wrapped in a PState
, or persistent state, which
contains persistence information about the user that is not part of
the domain model. You don’t need to know much of anything about a
PState
, except that you can call methods get
and modify
on it, to
work with the underlying User
inside.
In the yield clause of the for comprehension in this method,
created.get
retrieves the User
from the PState
. This in turn is
passed to a method that converts from a User
to a UserInfo
. Then
the for comprehension wraps this back up in a Future
, which is
exactly the kind of thing that Akka HTTP wants to work with.
One caveat here is that repo.create
might fail with a duplicate
key exception. There might already be a user that has either the same
username or email. So we call recover
on the resulting Future
and
convert the longevity DuplicateKeyValException
into a service-level
exception: either DuplicateUsernameException
or
DuplicateEmailException
:
import longevity.exceptions.persistence.DuplicateKeyValException
/** converts longevity duplicate key val exception into simbl exception */
private def handleDuplicateKeyVal(e: DuplicateKeyValException[_, _], info: UserInfo): Nothing = {
e.key match {
case User.keys.username =>
throw new DuplicateUsernameException(info.username)
case User.keys.email =>
throw new DuplicateEmailException(info.email)
}
}
Our Akka HTTP route responds to these exceptions by
producing a 409 Conflict
.