Skip to content

Instantly share code, notes, and snippets.

@junior-ales
Last active March 29, 2018 22:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save junior-ales/b08ffd0041235100f828f2b40e9c5fda to your computer and use it in GitHub Desktop.
Save junior-ales/b08ffd0041235100f828f2b40e9c5fda to your computer and use it in GitHub Desktop.
Exemplo do uso de Either e generics nos erros
trait ServiceError {
def errorMessage: String
}
case class HttpError(error: Error, code: Int) extends ServiceError {
override def errorMessage: String =
s"Error: ${error.getMessage}. Code: $code"
}
case class DbError(error: Error, dbName: String) extends ServiceError {
override def errorMessage: String =
s"Error: ${error.getMessage}. Database name: $dbName"
}
case class UserData(name: String, age: Int)
case class GithubData(username: String)
case class User(data: UserData, github: GithubData) {
def printIt: String =
s"The user ${data.name} is ${data.age} years old and " +
s"is in github under the username ${github.username}"
}
// Chamada pro banco ficticia, soh pra ilustrar
def getUserDataById(id: Int): Either[DbError, UserData] = {
if (id == 5)
Right(UserData("Ronaldo Nazario", 40))
else if (id == 8)
Right(UserData("Bebeto", 52))
else
Left(DbError(new Error("DB is down"), "footballPlayers"))
}
// Chamada pra api do github ficticia, soh pra ilustrar
def findGithubByName(name: String): Either[HttpError, GithubData] = {
if (name.equals("Ronaldo Nazario"))
Right(GithubData("ronaldinho9"))
else
Left(HttpError(new Error("API is down"), 500))
}
def getUser(id: Int): Either[ServiceError, User] = for {
user <- getUserDataById(id)
github <- findGithubByName(user.name)
} yield User(user, github)
/*
*
* Resultado do input sendo 5 = "The user Ronaldo Nazario is 40 years old and is in github under the username ronaldinho9"
* Resultado do input sendo 8 = "Error: API is down. Code: 500"
* Resultado de qualquer outro input = "Error: DB is down. Database name: footballPlayers"
*
*/
val res1: String = getUser(8).fold(
error => error.errorMessage,
user => user.printIt
)
// Mesma coisa que o res1
val res2: String = getUser(5) match {
case Right(u) => u.printIt
case Left(error) => error.errorMessage
}
// Aqui modifica soh os erros
val res3: Either[String, User] = getUser(4).left.map({
case HttpError(_, code) => s"Bad error code: $code"
case DbError(_, dbName) => s"Real bad player not found in DB: $dbName"
})
@jcsantosbr
Copy link

@junior-ales
Copy link
Author

Em vez de "Sem Either, usando Exception" não seria "Sem Either, usando Try"? A Exception tá deixando o polimorfismo mais semântico no caso, mas não substitui o Either.

O novo código tá substituindo uma monad (Either) por outra (Try) que nesse caso até faz sentido já que as chamadas são sempre passíveis de uma exceção (HTTP e DB). Mas tem situações que o Either seria melhor por ser mais flexível, por exemplo num caso aonde o erro é de regra de negócio (ex: se a função for chamada mais de 5 vezes não retorne o dado, retorne um erro) aonde usar uma exceção não seria o ideal.

@jcsantosbr
Copy link

@junior-ales: Nao exatamente, o Try tá sendo no último level apenas, nao na api... ali é a mesma coisa substituir por um try/catch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment