Skip to content

Commit

Permalink
refactor: rename Fail to Error and move into the domains package
Browse files Browse the repository at this point in the history
  • Loading branch information
yoshinorin committed Jul 15, 2024
1 parent ee63f9b commit 2cf2b39
Show file tree
Hide file tree
Showing 35 changed files with 106 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import cats.effect.IO
import cats.Monad
import net.yoshinorin.qualtet.domains.authors.{AuthorId, AuthorService, BCryptPassword, ResponseAuthor}
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import net.yoshinorin.qualtet.message.Fail.{NotFound, Unauthorized}
import net.yoshinorin.qualtet.domains.errors.{NotFound, Unauthorized}
import net.yoshinorin.qualtet.syntax.*
import org.slf4j.LoggerFactory

Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/net/yoshinorin/qualtet/auth/Jwt.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.github.plokhotnyuk.jsoniter_scala.macros.*
import com.github.plokhotnyuk.jsoniter_scala.core.*
import net.yoshinorin.qualtet.config.JwtConfig
import net.yoshinorin.qualtet.domains.authors.Author
import net.yoshinorin.qualtet.message.Fail.Unauthorized
import net.yoshinorin.qualtet.domains.errors.Unauthorized
import net.yoshinorin.qualtet.syntax.*
import org.slf4j.LoggerFactory
import pdi.jwt.algorithms.JwtAsymmetricAlgorithm
Expand Down
40 changes: 40 additions & 0 deletions src/main/scala/net/yoshinorin/qualtet/domains/Error.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package net.yoshinorin.qualtet.domains.errors

import net.yoshinorin.qualtet.http.ProblemDetailsError

sealed trait Error extends Exception

final case class NotFound(
title: String = "Not Found",
detail: String,
errors: Option[Seq[ProblemDetailsError]] = None
) extends Error

final case class Unauthorized(
title: String = "Unauthorized",
detail: String = "Unauthorized", // NOTE: no-need to set error details for secure reason. set default value instead.
errors: Option[Seq[ProblemDetailsError]] = None
) extends Error

final case class UnprocessableEntity(
title: String = "Unprocessable Entity",
detail: String,
errors: Option[Seq[ProblemDetailsError]] = None
) extends Error

final case class BadRequest(
title: String = "Bad Request",
detail: String,
errors: Option[Seq[ProblemDetailsError]] = None
) extends Error

final case class Forbidden(
title: String = "Forbidden",
detail: String,
errors: Option[Seq[ProblemDetailsError]] = None
) extends Error

final case class InternalServerError(
title: String = "Internal Server Error",
detail: String = "Internal Server Error"
) extends Error
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import cats.Monad
import cats.data.ContT
import cats.effect.IO
import net.yoshinorin.qualtet.domains.contentTypes.ContentTypeService
import net.yoshinorin.qualtet.message.Fail.NotFound
import net.yoshinorin.qualtet.domains.errors.NotFound
import net.yoshinorin.qualtet.infrastructure.db.Executer
import net.yoshinorin.qualtet.domains.contentTypes.ContentTypeId
import net.yoshinorin.qualtet.syntax.*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import cats.data.ContT
import cats.effect.IO
import cats.Monad
import net.yoshinorin.qualtet.domains.contentTypes.{ContentTypeId, ContentTypeService}
import net.yoshinorin.qualtet.message.Fail.NotFound
import net.yoshinorin.qualtet.domains.errors.NotFound
import net.yoshinorin.qualtet.domains.tags.TagName
import net.yoshinorin.qualtet.domains.series.SeriesName
import net.yoshinorin.qualtet.http.ArticlesQueryParameter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import java.time.ZonedDateTime
import com.github.plokhotnyuk.jsoniter_scala.macros.*
import com.github.plokhotnyuk.jsoniter_scala.core.*
import net.yoshinorin.qualtet.domains.{UlidConvertible, ValueExtender}
import net.yoshinorin.qualtet.message.Fail.{Unauthorized, UnprocessableEntity}
import net.yoshinorin.qualtet.domains.errors.{Unauthorized, UnprocessableEntity}
import net.yoshinorin.qualtet.syntax.*

import scala.util.matching.Regex
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package net.yoshinorin.qualtet.domains.authors
import cats.data.ContT
import cats.effect.IO
import cats.Monad
import net.yoshinorin.qualtet.message.Fail.InternalServerError
import net.yoshinorin.qualtet.domains.errors.InternalServerError
import net.yoshinorin.qualtet.infrastructure.db.Executer
import net.yoshinorin.qualtet.syntax.*

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import cats.data.ContT
import cats.effect.IO
import cats.Monad
import net.yoshinorin.qualtet.cache.CacheModule
import net.yoshinorin.qualtet.message.Fail.InternalServerError
import net.yoshinorin.qualtet.domains.errors.InternalServerError
import net.yoshinorin.qualtet.domains.Cacheable
import net.yoshinorin.qualtet.infrastructure.db.Executer
import net.yoshinorin.qualtet.syntax.*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import net.yoshinorin.qualtet.domains.externalResources.ExternalResources
import net.yoshinorin.qualtet.domains.robots.Attributes
import net.yoshinorin.qualtet.domains.series.SeriesName
import net.yoshinorin.qualtet.domains.tags.Tag
import net.yoshinorin.qualtet.message.Fail.BadRequest
import net.yoshinorin.qualtet.domains.errors.BadRequest
import net.yoshinorin.qualtet.syntax.*

opaque type ContentId = String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import net.yoshinorin.qualtet.domains.authors.{AuthorName, AuthorService}
import net.yoshinorin.qualtet.domains.contentSerializing.{ContentSerializing, ContentSerializingService}
import net.yoshinorin.qualtet.domains.contentTypes.ContentTypeService
import net.yoshinorin.qualtet.domains.externalResources.{ExternalResource, ExternalResourceKind, ExternalResourceService, ExternalResources}
import net.yoshinorin.qualtet.message.Fail.{InternalServerError, NotFound, UnprocessableEntity}
import net.yoshinorin.qualtet.domains.errors.{InternalServerError, NotFound, UnprocessableEntity}
import net.yoshinorin.qualtet.domains.contentTaggings.{ContentTagging, ContentTaggingService}
import net.yoshinorin.qualtet.domains.robots.{Attributes, Robots, RobotsService}
import net.yoshinorin.qualtet.domains.tags.{Tag, TagId, TagName, TagService}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.github.plokhotnyuk.jsoniter_scala.macros.*
import com.github.plokhotnyuk.jsoniter_scala.core.*
import net.yoshinorin.qualtet.domains.ValueExtender
import net.yoshinorin.qualtet.domains.contents.ContentId
import net.yoshinorin.qualtet.message.Fail.UnprocessableEntity
import net.yoshinorin.qualtet.domains.errors.UnprocessableEntity

opaque type ExternalResourceKind = String
object ExternalResourceKind extends ValueExtender[ExternalResourceKind] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.github.plokhotnyuk.jsoniter_scala.macros.*
import com.github.plokhotnyuk.jsoniter_scala.core.*
import net.yoshinorin.qualtet.domains.ValueExtender
import net.yoshinorin.qualtet.domains.contents.ContentId
import net.yoshinorin.qualtet.message.Fail.UnprocessableEntity
import net.yoshinorin.qualtet.domains.errors.UnprocessableEntity

opaque type Attributes = String
object Attributes extends ValueExtender[Attributes] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import cats.Monad
import cats.implicits.*
import net.yoshinorin.qualtet.config.SearchConfig
import net.yoshinorin.qualtet.infrastructure.db.Executer
import net.yoshinorin.qualtet.message.Fail.UnprocessableEntity
import net.yoshinorin.qualtet.domains.errors.UnprocessableEntity
import net.yoshinorin.qualtet.http.ProblemDetailsError
import net.yoshinorin.qualtet.types.Points
import net.yoshinorin.qualtet.syntax.*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package net.yoshinorin.qualtet.domains.series
import com.github.plokhotnyuk.jsoniter_scala.macros.*
import com.github.plokhotnyuk.jsoniter_scala.core.*
import net.yoshinorin.qualtet.domains.{Request, UlidConvertible, ValueExtender}
import net.yoshinorin.qualtet.message.Fail.BadRequest
import net.yoshinorin.qualtet.domains.errors.BadRequest
import net.yoshinorin.qualtet.syntax.*
import net.yoshinorin.qualtet.domains.articles.ResponseArticle

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import cats.effect.IO
import cats.Monad
import net.yoshinorin.qualtet.domains.articles.ArticleService
import net.yoshinorin.qualtet.infrastructure.db.Executer
import net.yoshinorin.qualtet.message.Fail.NotFound
import net.yoshinorin.qualtet.domains.errors.NotFound
import net.yoshinorin.qualtet.syntax.*
import wvlet.airframe.ulid.ULID

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import cats.Monad
import cats.implicits.*
import net.yoshinorin.qualtet.domains.contentTaggings.ContentTaggingService
import net.yoshinorin.qualtet.infrastructure.db.Executer
import net.yoshinorin.qualtet.message.Fail.NotFound
import net.yoshinorin.qualtet.domains.errors.NotFound
import net.yoshinorin.qualtet.domains.contents.ContentId
import net.yoshinorin.qualtet.syntax.*

Expand Down
13 changes: 6 additions & 7 deletions src/main/scala/net/yoshinorin/qualtet/http/AuthProvider.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import org.http4s.headers.Authorization
import org.slf4j.LoggerFactory
import net.yoshinorin.qualtet.domains.authors.ResponseAuthor
import net.yoshinorin.qualtet.auth.AuthService
import net.yoshinorin.qualtet.message.Fail
import net.yoshinorin.qualtet.message.Fail.{NotFound, Unauthorized}
import net.yoshinorin.qualtet.domains.errors.{Error, NotFound, Unauthorized}
import net.yoshinorin.qualtet.syntax.*

class AuthProvider[F[_]: Monad](
Expand All @@ -20,15 +19,15 @@ class AuthProvider[F[_]: Monad](
private val logger = LoggerFactory.getLogger(this.getClass)

// TODO: cleanup messy code
private def authUser: Kleisli[IO, Request[IO], Either[Fail, (ResponseAuthor, String)]] =
private def authUser: Kleisli[IO, Request[IO], Either[Error, (ResponseAuthor, String)]] =
Kleisli({ request =>
request.headers.get[Authorization].asEither[Fail](Unauthorized("Authorization header is none")) match {
case Left(f: Fail) => IO(Left(f))
request.headers.get[Authorization].asEither[Error](Unauthorized("Authorization header is none")) match {
case Left(f: Error) => IO(Left(f))
case Right(auth: Authorization) =>
val renderString = auth.credentials.renderString.replace("Bearer ", "").replace("bearer ", "")
for {
maybeAuthor <- authService.findAuthorFromJwtString(renderString)
author <- IO(maybeAuthor.asEither[Fail](NotFound(detail = "author not found")))
author <- IO(maybeAuthor.asEither[Error](NotFound(detail = "author not found")))
payload <- request.as[String]
} yield {
author match {
Expand All @@ -44,7 +43,7 @@ class AuthProvider[F[_]: Monad](
}
})

private def onFailure: AuthedRoutes[Fail, IO] = Kleisli { req =>
private def onFailure: AuthedRoutes[Error, IO] = Kleisli { req =>
OptionT.pure[IO](Response[IO](status = Status.Unauthorized))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package net.yoshinorin.qualtet.http

import com.github.plokhotnyuk.jsoniter_scala.core.*
import net.yoshinorin.qualtet.domains.Request
import net.yoshinorin.qualtet.message.Fail.InternalServerError
import net.yoshinorin.qualtet.message.Fail
import net.yoshinorin.qualtet.domains.errors.{BadRequest, Error, InternalServerError}
import net.yoshinorin.qualtet.syntax.*
import org.slf4j.LoggerFactory

Expand All @@ -13,17 +12,17 @@ trait RequestDecoder {

private val logger = LoggerFactory.getLogger(this.getClass)

def decode[T <: Request[T]](maybeJsonString: String): JsonValueCodec[T] ?=> Either[Fail, T] = {
def decode[T <: Request[T]](maybeJsonString: String): JsonValueCodec[T] ?=> Either[Error, T] = {
try {
Right(maybeJsonString.decode.postDecode)
} catch {
case NonFatal(t) =>
logger.error(t.getMessage())
t match {
case t: Fail => Left(t)
case t: Error => Left(t)
case t: JsonReaderException =>
// TODO: consider error message
Left(Fail.BadRequest(detail = "Wrong JSON format or missing required field. Please see API document."))
Left(BadRequest(detail = "Wrong JSON format or missing required field. Please see API document."))
case _ => Left(InternalServerError())
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,23 @@ import org.http4s.{Request, Response}
import org.http4s.Challenge
import org.http4s.headers.{`Content-Type`, `WWW-Authenticate`}
import com.github.plokhotnyuk.jsoniter_scala.core.*
import net.yoshinorin.qualtet.message.Fail
import net.yoshinorin.qualtet.domains.errors.{
BadRequest => DomainBadRequest,
Error,
Forbidden => DomainForbidden,
InternalServerError => DomainInternalServerError,
NotFound => DomainNotFound,
Unauthorized => DomainUnauthorized,
UnprocessableEntity => DomainUnprocessableEntity
}
import net.yoshinorin.qualtet.syntax.*

object ResponseTranslator {

// NOTE: can't use `ContextFunctions`.
private def failToResponse(f: Fail)(using req: Request[IO]): IO[Response[IO]] = {
private def failToResponse(f: Error)(using req: Request[IO]): IO[Response[IO]] = {
f match {
case e: Fail.NotFound =>
case e: DomainNotFound =>
NotFound(
ResponseProblemDetails(
title = e.title,
Expand All @@ -25,9 +33,9 @@ object ResponseTranslator {
).asJson,
`Content-Type`(MediaType.application.`problem+json`)
)
case e: Fail.Unauthorized =>
case e: DomainUnauthorized =>
Unauthorized(`WWW-Authenticate`(Challenge("Bearer", "Unauthorized")))
case e: Fail.UnprocessableEntity =>
case e: DomainUnprocessableEntity =>
UnprocessableEntity(
ResponseProblemDetails(
title = e.title,
Expand All @@ -38,7 +46,7 @@ object ResponseTranslator {
).asJson,
`Content-Type`(MediaType.application.`problem+json`)
)
case e: Fail.BadRequest =>
case e: DomainBadRequest =>
BadRequest(
ResponseProblemDetails(
title = e.title,
Expand All @@ -48,7 +56,7 @@ object ResponseTranslator {
).asJson,
`Content-Type`(MediaType.application.`problem+json`)
)
case e: Fail.Forbidden =>
case e: DomainForbidden =>
Forbidden(
ResponseProblemDetails(
title = e.title,
Expand All @@ -58,7 +66,7 @@ object ResponseTranslator {
).asJson,
`Content-Type`(MediaType.application.`problem+json`)
)
case e: Fail.InternalServerError =>
case e: DomainInternalServerError =>
InternalServerError(
ResponseProblemDetails(
title = e.title,
Expand All @@ -73,7 +81,7 @@ object ResponseTranslator {

def toResponse(e: Throwable): Request[IO] ?=> IO[Response[IO]] = {
e match {
case f: Fail => this.failToResponse(f)
case f: Error => this.failToResponse(f)
case _ => InternalServerError("Internal Server Error")
}
}
Expand Down
44 changes: 0 additions & 44 deletions src/main/scala/net/yoshinorin/qualtet/message/Fail.scala

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package net.yoshinorin.qualtet.auth

import cats.effect.IO
import net.yoshinorin.qualtet.domains.authors.ResponseAuthor
import net.yoshinorin.qualtet.message.Fail.{NotFound, Unauthorized}
import net.yoshinorin.qualtet.domains.errors.{NotFound, Unauthorized}
import net.yoshinorin.qualtet.Modules.*
import net.yoshinorin.qualtet.Modules
import net.yoshinorin.qualtet.fixture.Fixture.*
Expand Down
2 changes: 1 addition & 1 deletion src/test/scala/net/yoshinorin/qualtet/auth/JwtSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package net.yoshinorin.qualtet.auth

import cats.effect.IO
import net.yoshinorin.qualtet.domains.authors.{Author, AuthorDisplayName, AuthorId, AuthorName}
import net.yoshinorin.qualtet.message.Fail.Unauthorized
import net.yoshinorin.qualtet.domains.errors.Unauthorized
import net.yoshinorin.qualtet.Modules.*
import net.yoshinorin.qualtet.fixture.Fixture.validBCryptPassword
import net.yoshinorin.qualtet.validator.Validator
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package net.yoshinorin.qualtet.domains.authors

import net.yoshinorin.qualtet.domains.authors.{AuthorDisplayName, AuthorId, AuthorName, BCryptPassword}
import net.yoshinorin.qualtet.message.Fail.{Unauthorized, UnprocessableEntity}
import net.yoshinorin.qualtet.domains.errors.{Unauthorized, UnprocessableEntity}
import net.yoshinorin.qualtet.syntax.*
import net.yoshinorin.qualtet.fixture.Fixture.*
import org.scalatest.wordspec.AnyWordSpec
Expand Down
Loading

0 comments on commit 2cf2b39

Please sign in to comment.