2017-01-28 4 views
2

私はScalaとPlay Framework 2.5を使ってWebサービスを開発しています。私のアプリケーションは典型的な階層化アーキテクチャを持っています。私は以下のクラスを持っています:model.Userrepository.UserRepositoryservice.UserServicecontrollers.UserControllerそして私はExceptionを使わずに経営ロジックエラーを処理する良い方法をしようとしています。スカラのBuisnessロジックエラー処理

次の場合を考慮してください:新規ユーザーの登録要求。要求本体には、emailpasswordという2つのパラメータがあります。これらのパラメータは、UserService#registerUserに送られ、電子メールが有効で、そのような電子メールを持つユーザがすでに存在するかどうかがチェックされます。私の解決策はUserService#registerUserを結果としてEither[BuisnessFailure, Int]オブジェクトに戻すことです。 BuisnessFailureは形質であり、WrongEmailFormatFailureおよびUserAlreadyExistFailureによって継承されています。 電子メールが有効でない場合、UserService#registerUserLeft(WrongEmailFormatFailure)を返します。このような電子メールを持つユーザーがすでに存在する場合、UserService#registerUserLeft(UserAlreadyExistFailure)を返します。成功の場合、UserService#registerUserRight(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

良い質問ですが、http://softwareengineering.stackexchange.comでより適切になるでしょう – Jubobs

+1

@Jubobsリンクをありがとう。ソフトウェアエンジニアリングについて聞いたことがありません.stackexchange.com。 – alex

+1

私は別のサービスの検証を行いますので、他のサイトを参照するときには、よりテスト可能で再利用可能です –

答えて

4

これは私たちが私たちの最大のプロジェクトの一つのエラー処理に関するやったと私たちはすべての問題を持っていなかった正確に何です。 Eitherはそのように正確に使用する必要があります。エラーの場合はLeft、結果の場合はRightです。

  • これは、タイプセーフ
  • のコード
  • 同時性を心配する必要は

拡張性と保守性ではない唯一の点は、Scalaのアプリケーションのほとんどは非ブロック(非同期)しているように、ということです人々は Either[Error, Int]ではなく Future[Either[Error, Int]]を使用します。しかし、あなたがノンブロッキングのために行くことを決心したときはいつでも、 Futureの中に簡単に Eitherを入れることができ、私が言ったように、並行性の問題について心配する必要はありません。

関連する問題