Skip to content

Commit

Permalink
Merge pull request #1871 from softwaremill/optional-server-logic
Browse files Browse the repository at this point in the history
Extend the way server logic can be specified
  • Loading branch information
adamw authored Feb 16, 2022
2 parents bcaad0e + 28ec047 commit 77430c7
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
36 changes: 36 additions & 0 deletions core/src/main/scala/sttp/tapir/Endpoint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,24 @@ trait EndpointServerLogicOps[A, I, E, O, -R] { outer: Endpoint[A, I, E, O, R] =>
)(implicit eIsThrowable: E <:< Throwable, eClassTag: ClassTag[E], aIsUnit: A =:= Unit): ServerEndpoint.Full[Unit, Unit, I, E, O, R, F] =
ServerEndpoint.public(this.asInstanceOf[Endpoint[Unit, I, E, O, R]], recoverErrors1[I, E, O, F](f))

/** Like [[serverLogic]], but specialised to the case when the error type is `Unit` (e.g. a fixed status code), and the result of the
* logic function is an option. A `None` is then treated as an error response.
*/
def serverLogicOption[F[_]](
f: I => F[Option[O]]
)(implicit aIsUnit: A =:= Unit, eIsUnit: E =:= Unit): ServerEndpoint.Full[Unit, Unit, I, Unit, O, R, F] = {
import sttp.monad.syntax._
ServerEndpoint.public(
this.asInstanceOf[Endpoint[Unit, I, Unit, O, R]],
implicit m =>
i =>
f(i).map {
case None => Left(())
case Some(v) => Right(v)
}
)
}

//

/** Combine this endpoint description with a function, which implements the security logic of the endpoint.
Expand Down Expand Up @@ -430,6 +448,24 @@ trait EndpointServerLogicOps[A, I, E, O, -R] { outer: Endpoint[A, I, E, O, R] =>
f: A => F[U]
)(implicit eIsThrowable: E <:< Throwable, eClassTag: ClassTag[E]): PartialServerEndpoint[A, U, I, E, O, R, F] =
PartialServerEndpoint(this, recoverErrors1[A, E, U, F](f))

/** Like [[serverSecurityLogic]], but specialised to the case when the error type is `Unit` (e.g. a fixed status code), and the result of
* the logic function is an option. A `None` is then treated as an error response.
*/
def serverSecurityLogicOption[U, F[_]](
f: A => F[Option[U]]
)(implicit eIsUnit: E =:= Unit): PartialServerEndpoint[A, U, I, Unit, O, R, F] = {
import sttp.monad.syntax._
PartialServerEndpoint(
this.asInstanceOf[Endpoint[A, I, Unit, O, R]],
implicit m =>
a =>
f(a).map {
case None => Left(())
case Some(v) => Right(v)
}
)
}
}

case class EndpointInfo(
Expand Down
13 changes: 13 additions & 0 deletions core/src/main/scala/sttp/tapir/server/PartialServerEndpoint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,17 @@ case class PartialServerEndpoint[A, U, I, E, O, -R, F[_]](
f: U => I => F[O]
)(implicit eIsThrowable: E <:< Throwable, eClassTag: ClassTag[E]): ServerEndpoint.Full[A, U, I, E, O, R, F] =
ServerEndpoint(endpoint, securityLogic, recoverErrors2[U, I, E, O, F](f))

def serverLogicOption(f: U => I => F[Option[O]])(implicit eIsUnit: E =:= Unit): ServerEndpoint.Full[A, U, I, Unit, O, R, F] =
ServerEndpoint(
endpoint.asInstanceOf[Endpoint[A, I, Unit, O, R]],
securityLogic.asInstanceOf[MonadError[F] => A => F[Either[Unit, U]]],
implicit m =>
u =>
i =>
f(u)(i).map {
case None => Left(())
case Some(v) => Right(v)
}
)
}

0 comments on commit 77430c7

Please sign in to comment.