我正在使用Scala和Play Framework 2.5开发Web服务。我的应用有典型的分层架构。我有以下课程:model.User
,repository.UserRepository
,service.UserService
和controllers.UserController
我正试图在不使用Exception
的情况下处理商务逻辑错误的好方法。
考虑以下情况:收到了注册新用户的请求。请求正文中有两个参数:email
和password
。这些参数被输入UserService#registerUser
,检查电子邮件是否有效以及是否已存在此类电子邮件的用户。我的解决方案是使UserService#registerUser
返回Either[BuisnessFailure, Int]
个对象。 BuisnessFailure
是一种特质,由WrongEmailFormatFailure
和UserAlreadyExistFailure
继承。
如果电子邮件无效,则UserService#registerUser
会返回Left(WrongEmailFormatFailure)
。如果已存在此类电子邮件的用户,则UserService#registerUser
会返回Left(UserAlreadyExistFailure)
。如果成功,UserService#registerUser
会返回Right(userRepository.create(User(email, password))
。之后,在controllers.UserController
我可以使用模式匹配处理此案例并发送适当的响应。
那么,这种方法是否足以处理类似情况?请在下面找到我的代码:
用户:
package model
case class User(email: String, password: String)
UserRepository:
package repository
import model.User
class UserRepository {
def create(user: User): Int = ???
def find(email: String): Option[User] = ???
}
UserService:
package service
import model.User
import repository.UserRepository
import util.{BuisnessFailure, UserAlreadyExistFailure, WrongEmailFormatFailure}
class UserService {
private val userRepository: UserRepository = ???
def registerUser(email: String, password: String): Either[BuisnessFailure, Int] = {
if (userAlreadyExists(email))
Left(UserAlreadyExistFailure)
else
if (!isEmailValid(email))
Left(WrongEmailFormatFailure)
else
Right(userRepository.create(User(email, password)))
}
private def isEmailValid(email: String): Boolean = ???
private def userAlreadyExists(email: String): Boolean = ???
}
UserController中:
package controller
import service.UserService
import util.{UserAlreadyExistFailure, WrongEmailFormatFailure}
class UserController extends play.api.Controller {
private val userService = new UserService
def signUp() = Action(parse.json) { implicit request =>
//obtaining email and password parameters from request body
val email = ???
val password = ???
userService.registerUser(email, password) match {
case Left(WrongEmailFormatFailure) => // send 400 code and appropriate error message
case Left(UserAlreadyExistFailure) => // send 400 code and appropriate error message
case Right(_) => // send response with 200 code
}
}
}
BuisnessFailure:
package util
sealed trait BuisnessFailure
case object UserAlreadyExistFailure extends BuisnessFailure
case object WrongEmailFormatFailure extends BuisnessFailure
答案 0 :(得分:4)
这正是我们针对一个最大项目的错误处理所做的,我们没有遇到任何问题。 Either
应该像这样使用。错误Left
,结果Right
。
唯一的一点是,由于大多数Scala应用程序都是非阻止(异步),因此人们会使用Future[Either[Error, Int]]
而不是Either[Error, Int]
。但是,它仍然没关系,因为每当你决定采用非阻塞时,你可以轻松地将Either
包裹在Future
内,正如我告诉你的那样,不用担心并发问题。