-
Notifications
You must be signed in to change notification settings - Fork 422
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move Id alias to core. Add serverLogicSync & other variants to Endpoi…
…nt. (#3789)
- Loading branch information
Showing
71 changed files
with
658 additions
and
367 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
139 changes: 139 additions & 0 deletions
139
core/src/main/scala/sttp/tapir/server/PartialServerEndpointSync.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
package sttp.tapir.server | ||
|
||
import sttp.shared.Identity | ||
import sttp.tapir._ | ||
import sttp.tapir.internal._ | ||
|
||
import scala.reflect.ClassTag | ||
|
||
/** Direct-style variant of [[PartialServerEndpoint]], using the [[Identity]] "effect". */ | ||
case class PartialServerEndpointSync[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, -R]( | ||
endpoint: Endpoint[SECURITY_INPUT, INPUT, ERROR_OUTPUT, OUTPUT, R], | ||
securityLogic: SECURITY_INPUT => Either[ERROR_OUTPUT, PRINCIPAL] | ||
) extends EndpointInputsOps[SECURITY_INPUT, INPUT, ERROR_OUTPUT, OUTPUT, R] | ||
with EndpointOutputsOps[SECURITY_INPUT, INPUT, ERROR_OUTPUT, OUTPUT, R] | ||
with EndpointErrorOutputVariantsOps[SECURITY_INPUT, INPUT, ERROR_OUTPUT, OUTPUT, R] | ||
with EndpointInfoOps[R] | ||
with EndpointMetaOps { outer => | ||
override type ThisType[-_R] = PartialServerEndpointSync[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, _R] | ||
override type EndpointType[_A, _I, _E, _O, -_R] = PartialServerEndpointSync[_A, PRINCIPAL, _I, _E, _O, _R] | ||
|
||
override def securityInput: EndpointInput[SECURITY_INPUT] = endpoint.securityInput | ||
override def input: EndpointInput[INPUT] = endpoint.input | ||
override def errorOutput: EndpointOutput[ERROR_OUTPUT] = endpoint.errorOutput | ||
override def output: EndpointOutput[OUTPUT] = endpoint.output | ||
override def info: EndpointInfo = endpoint.info | ||
|
||
override private[tapir] def withInput[I2, R2]( | ||
input: EndpointInput[I2] | ||
): PartialServerEndpointSync[SECURITY_INPUT, PRINCIPAL, I2, ERROR_OUTPUT, OUTPUT, R with R2] = | ||
copy(endpoint = endpoint.copy(input = input)) | ||
override private[tapir] def withOutput[O2, R2](output: EndpointOutput[O2]) = copy(endpoint = endpoint.copy(output = output)) | ||
override private[tapir] def withErrorOutputVariant[E2, R2]( | ||
errorOutput: EndpointOutput[E2], | ||
embedE: ERROR_OUTPUT => E2 | ||
): PartialServerEndpointSync[SECURITY_INPUT, PRINCIPAL, INPUT, E2, OUTPUT, R with R2] = | ||
this.copy( | ||
endpoint = endpoint.copy(errorOutput = errorOutput), | ||
securityLogic = a => | ||
securityLogic(a) match { | ||
case Left(e) => Left(embedE(e)) | ||
case Right(o) => Right(o) | ||
} | ||
) | ||
override private[tapir] def withInfo(info: EndpointInfo) = copy(endpoint = endpoint.copy(info = info)) | ||
|
||
override protected def showType: String = "PartialServerEndpoint" | ||
|
||
def handle( | ||
f: PRINCIPAL => INPUT => Either[ERROR_OUTPUT, OUTPUT] | ||
): ServerEndpoint.Full[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, R, Identity] = | ||
ServerEndpoint[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, R, Identity](endpoint, _ => securityLogic, _ => f) | ||
|
||
def handleSuccess( | ||
f: PRINCIPAL => INPUT => OUTPUT | ||
): ServerEndpoint.Full[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, R, Identity] = | ||
ServerEndpoint[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, R, Identity]( | ||
endpoint, | ||
_ => securityLogic, | ||
_ => u => i => Right(f(u)(i)) | ||
) | ||
|
||
def handleError( | ||
f: PRINCIPAL => INPUT => ERROR_OUTPUT | ||
): ServerEndpoint.Full[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, R, Identity] = | ||
ServerEndpoint[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, R, Identity]( | ||
endpoint, | ||
_ => securityLogic, | ||
_ => u => i => Left(f(u)(i)) | ||
) | ||
|
||
def handleRecoverErrors( | ||
f: PRINCIPAL => INPUT => OUTPUT | ||
)(implicit | ||
eIsThrowable: ERROR_OUTPUT <:< Throwable, | ||
eClassTag: ClassTag[ERROR_OUTPUT] | ||
): ServerEndpoint.Full[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, R, Identity] = | ||
ServerEndpoint[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, R, Identity]( | ||
endpoint, | ||
_ => securityLogic, | ||
recoverErrors2[PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, Identity](f) | ||
) | ||
|
||
def handleOption(f: PRINCIPAL => INPUT => Option[OUTPUT])(implicit | ||
eIsUnit: ERROR_OUTPUT =:= Unit | ||
): ServerEndpoint.Full[SECURITY_INPUT, PRINCIPAL, INPUT, Unit, OUTPUT, R, Identity] = | ||
ServerEndpoint[SECURITY_INPUT, PRINCIPAL, INPUT, Unit, OUTPUT, R, Identity]( | ||
endpoint.asInstanceOf[Endpoint[SECURITY_INPUT, INPUT, Unit, OUTPUT, R]], | ||
_ => securityLogic.asInstanceOf[SECURITY_INPUT => Either[Unit, PRINCIPAL]], | ||
_ => | ||
u => | ||
i => | ||
f(u)(i) match { | ||
case None => Left(()) | ||
case Some(v) => Right(v) | ||
} | ||
) | ||
|
||
/** If the error type is an `Either`, e.g. when using `errorOutEither`, this method accepts server logic that returns either success or | ||
* the `Right` error type. Use of this method avoids having to wrap the returned error in `Right`. | ||
*/ | ||
def handleRightErrorOrSuccess[LE, RE]( | ||
f: PRINCIPAL => INPUT => Either[RE, OUTPUT] | ||
)(implicit | ||
eIsEither: Either[LE, RE] =:= ERROR_OUTPUT | ||
): ServerEndpoint.Full[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, R, Identity] = | ||
ServerEndpoint[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, R, Identity]( | ||
endpoint, | ||
_ => securityLogic, | ||
_ => | ||
u => | ||
i => { | ||
f(u)(i) match { | ||
case Left(e) => Left(Right(e)) | ||
case Right(r) => Right(r) | ||
} | ||
} | ||
) | ||
|
||
/** If the error type is an `Either`, e.g. when using `errorOutEither`, this method accepts server logic that returns either success or | ||
* the `Left` error type. Use of this method avoids having to wrap the returned error in `Left`. | ||
*/ | ||
def handleLeftErrorOrSuccess[LE, RE]( | ||
f: PRINCIPAL => INPUT => Either[LE, OUTPUT] | ||
)(implicit | ||
eIsEither: Either[LE, RE] =:= ERROR_OUTPUT | ||
): ServerEndpoint.Full[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, R, Identity] = | ||
ServerEndpoint[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, OUTPUT, R, Identity]( | ||
endpoint, | ||
_ => securityLogic, | ||
_ => | ||
u => | ||
i => { | ||
f(u)(i) match { | ||
case Left(e) => Left(Left(e)) | ||
case Right(r) => Right(r) | ||
} | ||
} | ||
) | ||
} |
111 changes: 111 additions & 0 deletions
111
core/src/main/scala/sttp/tapir/server/PartialServerEndpointWithSecurityOutputSync.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package sttp.tapir.server | ||
|
||
import sttp.monad.IdentityMonad | ||
import sttp.shared.Identity | ||
import sttp.tapir._ | ||
import sttp.tapir.internal._ | ||
|
||
import scala.reflect.ClassTag | ||
|
||
/** Direct-style variant of [[PartialServerEndpointWithSecurityOutput]], using the [[Identity]] "effect". */ | ||
case class PartialServerEndpointWithSecurityOutputSync[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, SECURITY_OUTPUT, OUTPUT, -R]( | ||
securityOutput: EndpointOutput[SECURITY_OUTPUT], | ||
endpoint: Endpoint[SECURITY_INPUT, INPUT, ERROR_OUTPUT, OUTPUT, R], | ||
securityLogic: SECURITY_INPUT => Either[ERROR_OUTPUT, (SECURITY_OUTPUT, PRINCIPAL)] | ||
) extends EndpointInputsOps[SECURITY_INPUT, INPUT, ERROR_OUTPUT, OUTPUT, R] | ||
with EndpointOutputsOps[SECURITY_INPUT, INPUT, ERROR_OUTPUT, OUTPUT, R] | ||
with EndpointErrorOutputVariantsOps[SECURITY_INPUT, INPUT, ERROR_OUTPUT, OUTPUT, R] | ||
with EndpointInfoOps[R] | ||
with EndpointMetaOps { outer => | ||
override type ThisType[-_R] = | ||
PartialServerEndpointWithSecurityOutputSync[SECURITY_INPUT, PRINCIPAL, INPUT, ERROR_OUTPUT, SECURITY_OUTPUT, OUTPUT, _R] | ||
override type EndpointType[_A, _I, _E, _O, -_R] = | ||
PartialServerEndpointWithSecurityOutputSync[_A, PRINCIPAL, _I, _E, SECURITY_OUTPUT, _O, _R] | ||
|
||
override def securityInput: EndpointInput[SECURITY_INPUT] = endpoint.securityInput | ||
override def input: EndpointInput[INPUT] = endpoint.input | ||
override def errorOutput: EndpointOutput[ERROR_OUTPUT] = endpoint.errorOutput | ||
override def output: EndpointOutput[OUTPUT] = endpoint.output | ||
override def info: EndpointInfo = endpoint.info | ||
|
||
override private[tapir] def withInput[I2, R2]( | ||
input: EndpointInput[I2] | ||
): PartialServerEndpointWithSecurityOutputSync[SECURITY_INPUT, PRINCIPAL, I2, ERROR_OUTPUT, SECURITY_OUTPUT, OUTPUT, R with R2] = | ||
copy(endpoint = endpoint.copy(input = input)) | ||
override private[tapir] def withOutput[O2, R2](output: EndpointOutput[O2]) = copy(endpoint = endpoint.copy(output = output)) | ||
override private[tapir] def withErrorOutputVariant[E2, R2]( | ||
errorOutput: EndpointOutput[E2], | ||
embedE: ERROR_OUTPUT => E2 | ||
): PartialServerEndpointWithSecurityOutputSync[SECURITY_INPUT, PRINCIPAL, INPUT, E2, SECURITY_OUTPUT, OUTPUT, R with R2] = | ||
this.copy( | ||
endpoint = endpoint.copy(errorOutput = errorOutput), | ||
securityLogic = a => | ||
securityLogic(a) match { | ||
case Left(e) => Left(embedE(e)) | ||
case Right(o) => Right(o) | ||
} | ||
) | ||
override private[tapir] def withInfo(info: EndpointInfo) = copy(endpoint = endpoint.copy(info = info)) | ||
|
||
override protected def showType: String = "PartialServerEndpointWithSecurityOutput" | ||
|
||
def handle( | ||
f: PRINCIPAL => INPUT => Either[ERROR_OUTPUT, OUTPUT] | ||
): ServerEndpoint.Full[SECURITY_INPUT, (SECURITY_OUTPUT, PRINCIPAL), INPUT, ERROR_OUTPUT, (SECURITY_OUTPUT, OUTPUT), R, Identity] = | ||
ServerEndpoint[SECURITY_INPUT, (SECURITY_OUTPUT, PRINCIPAL), INPUT, ERROR_OUTPUT, (SECURITY_OUTPUT, OUTPUT), R, Identity]( | ||
endpoint.prependOut(securityOutput), | ||
_ => securityLogic, | ||
_ => so_u => i => f(so_u._2)(i).right.map(o => (so_u._1, o)) | ||
) | ||
|
||
def handleSuccess( | ||
f: PRINCIPAL => INPUT => OUTPUT | ||
): ServerEndpoint.Full[SECURITY_INPUT, (SECURITY_OUTPUT, PRINCIPAL), INPUT, ERROR_OUTPUT, (SECURITY_OUTPUT, OUTPUT), R, Identity] = | ||
ServerEndpoint[SECURITY_INPUT, (SECURITY_OUTPUT, PRINCIPAL), INPUT, ERROR_OUTPUT, (SECURITY_OUTPUT, OUTPUT), R, Identity]( | ||
endpoint.prependOut(securityOutput), | ||
_ => securityLogic, | ||
_ => so_u => i => Right((so_u._1, f(so_u._2)(i))) | ||
) | ||
|
||
def handleError( | ||
f: PRINCIPAL => INPUT => ERROR_OUTPUT | ||
): ServerEndpoint.Full[SECURITY_INPUT, (SECURITY_OUTPUT, PRINCIPAL), INPUT, ERROR_OUTPUT, (SECURITY_OUTPUT, OUTPUT), R, Identity] = | ||
ServerEndpoint[SECURITY_INPUT, (SECURITY_OUTPUT, PRINCIPAL), INPUT, ERROR_OUTPUT, (SECURITY_OUTPUT, OUTPUT), R, Identity]( | ||
endpoint.prependOut(securityOutput), | ||
_ => securityLogic, | ||
_ => so_u => i => Left(f(so_u._2)(i)) | ||
) | ||
|
||
def handleRecoverErrors( | ||
f: PRINCIPAL => INPUT => OUTPUT | ||
)(implicit | ||
eIsThrowable: ERROR_OUTPUT <:< Throwable, | ||
eClassTag: ClassTag[ERROR_OUTPUT] | ||
): ServerEndpoint.Full[SECURITY_INPUT, (SECURITY_OUTPUT, PRINCIPAL), INPUT, ERROR_OUTPUT, (SECURITY_OUTPUT, OUTPUT), R, Identity] = | ||
ServerEndpoint[SECURITY_INPUT, (SECURITY_OUTPUT, PRINCIPAL), INPUT, ERROR_OUTPUT, (SECURITY_OUTPUT, OUTPUT), R, Identity]( | ||
endpoint.prependOut(securityOutput), | ||
_ => securityLogic, | ||
_ => | ||
recoverErrors2[(SECURITY_OUTPUT, PRINCIPAL), INPUT, ERROR_OUTPUT, (SECURITY_OUTPUT, OUTPUT), Identity](so_u => | ||
i => (so_u._1, f(so_u._2)(i)) | ||
)( | ||
implicitly, | ||
implicitly | ||
)(IdentityMonad) | ||
) | ||
|
||
def handleOption(f: PRINCIPAL => INPUT => Option[OUTPUT])(implicit | ||
eIsUnit: ERROR_OUTPUT =:= Unit | ||
): ServerEndpoint.Full[SECURITY_INPUT, (SECURITY_OUTPUT, PRINCIPAL), INPUT, Unit, (SECURITY_OUTPUT, OUTPUT), R, Identity] = | ||
ServerEndpoint[SECURITY_INPUT, (SECURITY_OUTPUT, PRINCIPAL), INPUT, Unit, (SECURITY_OUTPUT, OUTPUT), R, Identity]( | ||
endpoint.prependOut(securityOutput).asInstanceOf[Endpoint[SECURITY_INPUT, INPUT, Unit, (SECURITY_OUTPUT, OUTPUT), R]], | ||
_ => securityLogic.asInstanceOf[SECURITY_INPUT => Identity[Either[Unit, (SECURITY_OUTPUT, PRINCIPAL)]]], | ||
_ => | ||
so_u => | ||
i => | ||
f(so_u._2)(i) match { | ||
case None => Left(()) | ||
case Some(v) => Right((so_u._1, v)) | ||
} | ||
) | ||
} |
Oops, something went wrong.