Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add info about failing discrimintator to UnknownErrorResponse #1575

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 41 additions & 17 deletions modules/core/src/smithy4s/http/HttpErrorSelector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,14 @@ object HttpErrorSelector {
def apply[F[_]: Covariant, E](
maybeErrorSchema: Option[ErrorSchema[E]],
compiler: CachedSchemaCompiler[F]
): HttpDiscriminator => Option[F[E]] = maybeErrorSchema match {
case None => _ => None
): HttpDiscriminator => Option[F[E]] =
makeWithReason(maybeErrorSchema, compiler).andThen(_.toOption)

def makeWithReason[F[_]: Covariant, E](
maybeErrorSchema: Option[ErrorSchema[E]],
compiler: CachedSchemaCompiler[F]
): HttpDiscriminator => Either[String, F[E]] = maybeErrorSchema match {
case None => _ => Left("error schema not found")
case Some(errorschema) =>
new HttpErrorSelector[F, E](
errorschema.alternatives,
Expand All @@ -61,21 +67,28 @@ object HttpErrorSelector {
def asThrowable[F[_]: Covariant, E](
maybeErrorSchema: Option[ErrorSchema[E]],
compiler: CachedSchemaCompiler[F]
): HttpDiscriminator => Option[F[Throwable]] = maybeErrorSchema match {
case None => _ => None
case Some(errorschema) =>
new HttpErrorSelector[F, E](
errorschema.alternatives,
compiler
).andThen(_.map(Covariant[F].map(_)(errorschema.unliftError)))
}
): HttpDiscriminator => Option[F[Throwable]] =
asThrowableWithReason(maybeErrorSchema, compiler).andThen(_.toOption)

def asThrowableWithReason[F[_]: Covariant, E](
maybeErrorSchema: Option[ErrorSchema[E]],
compiler: CachedSchemaCompiler[F]
): HttpDiscriminator => Either[String, F[Throwable]] =
maybeErrorSchema match {
case None => _ => Left("error schema not found")
case Some(errorschema) =>
new HttpErrorSelector[F, E](
errorschema.alternatives,
compiler
).andThen(_.map(Covariant[F].map(_)(errorschema.unliftError)))
}

}

private[http] final class HttpErrorSelector[F[_]: Covariant, E](
alts: Vector[Alt[E, _]],
compiler: CachedSchemaCompiler[F]
) extends (HttpDiscriminator => Option[F[E]]) {
) extends (HttpDiscriminator => Either[String, F[E]]) {

type ConstF[A] = F[E]
val cachedDecoders: PolyFunction[Alt[E, *], ConstF] =
Expand All @@ -101,7 +114,7 @@ private[http] final class HttpErrorSelector[F[_]: Covariant, E](

def apply(
discriminator: HttpDiscriminator
): Option[F[E]] = {
): Either[String, F[E]] = {
val alt = getPreciseAlternative(discriminator)
alt.map(cachedDecoders(_))
}
Expand Down Expand Up @@ -170,13 +183,24 @@ private[http] final class HttpErrorSelector[F[_]: Covariant, E](

private[http] def getPreciseAlternative(
discriminator: HttpDiscriminator
): Option[Alt[E, _]] = {
): Either[String, Alt[E, _]] = {
import HttpDiscriminator._
discriminator match {
case FullId(shapeId) => byShapeId.get(shapeId)
case NameOnly(name) => byName.get(name)
case StatusCode(int) => byStatusCode(int)
case Undetermined => None
case FullId(shapeId) =>
byShapeId
.get(shapeId)
.map(Right(_))
.getOrElse(Left(s"Couldn't match by fullId: $shapeId"))
case NameOnly(name) =>
byName
.get(name)
.map(Right(_))
.getOrElse(Left(s"Couldn't match by name: $name"))
case StatusCode(int) =>
byStatusCode(int)
.map(Right(_))
.getOrElse(Left(s"Couldn't match by statucCode: $int"))
case Undetermined => Left("The error shape could not be determined")
}
}
}
14 changes: 8 additions & 6 deletions modules/core/src/smithy4s/http/HttpResponse.scala
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ object HttpResponse {
): Decoder[F, Body, E] =
discriminating(
discriminate,
HttpErrorSelector(maybeErrorSchema, decoderCompiler),
HttpErrorSelector.makeWithReason(maybeErrorSchema, decoderCompiler),
toStrict
)

Expand All @@ -220,7 +220,8 @@ object HttpResponse {
): Decoder[F, Body, Throwable] =
discriminating(
discriminate,
HttpErrorSelector.asThrowable(maybeErrorSchema, decoderCompiler),
HttpErrorSelector
.asThrowableWithReason(maybeErrorSchema, decoderCompiler),
toStrict
)

Expand All @@ -230,7 +231,7 @@ object HttpResponse {
*/
private def discriminating[F[_], Body, Discriminator, E](
discriminate: HttpResponse[Body] => F[Discriminator],
select: Discriminator => Option[Decoder[F, Body, E]],
select: Discriminator => Either[String, Decoder[F, Body, E]],
toStrict: Body => F[(Body, Blob)]
)(implicit F: MonadThrowLike[F]): Decoder[F, Body, E] =
new Decoder[F, Body, E] {
Expand All @@ -239,13 +240,14 @@ object HttpResponse {
val strictResponse = response.copy(body = strictBody)
F.flatMap(discriminate(strictResponse)) { discriminator =>
select(discriminator) match {
case Some(decoder) => decoder.decode(strictResponse)
case None =>
case Right(decoder) => decoder.decode(strictResponse)
case Left(errors) =>
F.raiseError(
smithy4s.http.UnknownErrorResponse(
response.statusCode,
response.headers,
bodyBlob.toUTF8String
bodyBlob.toUTF8String,
errors
)
)
}
Expand Down
3 changes: 2 additions & 1 deletion modules/core/src/smithy4s/http/UnknownErrorResponse.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ package smithy4s.http
case class UnknownErrorResponse(
code: Int,
headers: Map[CaseInsensitive, Seq[String]],
body: String
body: String,
error: String
) extends Throwable {
override def getMessage(): String =
s"status $code, headers: $headers, body:\n$body"
Expand Down
Loading