Skip to content

Commit

Permalink
Provide Authentication information via EndpointExecutor (#3019) (#3026)
Browse files Browse the repository at this point in the history
  • Loading branch information
987Nabil authored Aug 24, 2024
1 parent 719fb15 commit a8b432d
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import zio.http.Header.Authorization
import zio.http._
import zio.http.codec.PathCodec.path
import zio.http.codec._
import zio.http.endpoint.AuthType.None
import zio.http.endpoint._
import zio.http.endpoint.openapi.{OpenAPIGen, SwaggerUI}

Expand Down Expand Up @@ -43,11 +44,11 @@ object EndpointExamples extends ZIOAppDefault {
val locator =
EndpointLocator.fromURL(URL.decode("http://localhost:8080").toOption.get)

val executor: EndpointExecutor =
val executor: EndpointExecutor[Any, Unit] =
EndpointExecutor(client, locator)

val x1 = getUser(42)
val x2 = getUserPosts(42, 200, "adam")
val x1: Invocation[Int, Int, ZNothing, Int, None] = getUser(42)
val x2 = getUserPosts(42, 200, "adam")

val result1: ZIO[Scope, Nothing, Int] = executor(x1)
val result2: ZIO[Scope, Nothing, List[String]] = executor(x2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ object ServerSentEventEndpointClient extends ZIOAppDefault {
val locator: EndpointLocator = EndpointLocator.fromURL(url"http://localhost:8080")

private val invocation
: Invocation[Unit, Unit, ZNothing, ZStream[Any, Nothing, ServerSentEvent[String]], AuthType.None, Unit] =
: Invocation[Unit, Unit, ZNothing, ZStream[Any, Nothing, ServerSentEvent[String]], AuthType.None] =
ServerSentEventEndpoint.sseEndpoint(())

override def run: ZIO[Any with ZIOAppArgs with Scope, Any, Any] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ object TestCliClient extends zio.ZIOAppDefault with TestCliEndpoints {
Scope.default,
)

lazy val clientExample: URIO[EndpointExecutor & Scope, Unit] =
lazy val clientExample: URIO[EndpointExecutor[Any, Unit] & Scope, Unit] =
for {
executor <- ZIO.service[EndpointExecutor]
executor <- ZIO.service[EndpointExecutor[Any, Unit]]
_ <- executor(getUser(42, Location.parse("some-location").toOption.get)).debug("result1")
_ <- executor(getUserPosts(42, 200, "adam")).debug("result2")
_ <- executor(createUser(User(2, "john", Some("[email protected]")))).debug("result3")
Expand Down
20 changes: 10 additions & 10 deletions zio-http/jvm/src/test/scala/zio/http/endpoint/AuthSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ object AuthSpec extends ZIOSpecDefault {
val response = for {
client <- ZIO.service[Client]
locator = EndpointLocator.fromURL(url"http://localhost:8080")
executor = EndpointExecutor(client, locator)
invocation = endpoint(Header.Authorization.Basic("admin", "admin".reverse))
executor = EndpointExecutor(client, locator, Header.Authorization.Basic("admin", "admin".reverse))
invocation = endpoint(())
response <- ZIO.scoped(executor(invocation))
} yield response

Expand All @@ -165,16 +165,16 @@ object AuthSpec extends ZIOSpecDefault {
val responseBasic = for {
client <- ZIO.service[Client]
locator = EndpointLocator.fromURL(url"http://localhost:8080")
executor = EndpointExecutor(client, locator)
invocation = endpoint(Left(Header.Authorization.Basic("admin", "admin".reverse)))
executor = EndpointExecutor(client, locator, Left(Header.Authorization.Basic("admin", "admin".reverse)))
invocation = endpoint(())
response <- ZIO.scoped(executor(invocation))
} yield response

val responseBearer = for {
client <- ZIO.service[Client]
locator = EndpointLocator.fromURL(url"http://localhost:8080")
executor = EndpointExecutor(client, locator)
invocation = endpoint(Right(Header.Authorization.Bearer("admin")))
executor = EndpointExecutor(client, locator, Right(Header.Authorization.Bearer("admin")))
invocation = endpoint(())
response <- ZIO.scoped(executor(invocation))
} yield response

Expand All @@ -199,8 +199,8 @@ object AuthSpec extends ZIOSpecDefault {
val response = for {
client <- ZIO.service[Client]
locator = EndpointLocator.fromURL(url"http://localhost:8080")
executor = EndpointExecutor(client, locator)
invocation = endpoint("admin")
executor = EndpointExecutor(client, locator, "admin")
invocation = endpoint(())
response <- ZIO.scoped(executor(invocation))
} yield response

Expand All @@ -223,8 +223,8 @@ object AuthSpec extends ZIOSpecDefault {
val response = for {
client <- ZIO.service[Client]
locator = EndpointLocator.fromURL(url"http://localhost:8080")
executor = EndpointExecutor(client, locator)
invocation = endpoint(1, Header.Authorization.Basic("admin", "admin".reverse))
executor = EndpointExecutor(client, locator, Header.Authorization.Basic("admin", "admin".reverse))
invocation = endpoint(1)
response <- ZIO.scoped(executor(invocation))
} yield response

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ object RoundtripSpec extends ZIOHttpSpec {
implicit val schema: Schema[PostWithAge] = DeriveSchema.gen[PostWithAge]
}

def makeExecutor(client: Client, port: Int): EndpointExecutor = {
def makeExecutor(client: Client, port: Int) = {
val locator = EndpointLocator.fromURL(
URL.decode(s"http://localhost:$port").toOption.get,
)
Expand Down Expand Up @@ -136,7 +136,7 @@ object RoundtripSpec extends ZIOHttpSpec {
port <- Server.install(route)
executorLayer = ZLayer(ZIO.service[Client].map(makeExecutor(_, port)))
out <- ZIO
.service[EndpointExecutor]
.service[EndpointExecutor[Any, Unit]]
.flatMap { executor =>
executor.apply(endpoint.apply(in))
}
Expand All @@ -151,7 +151,7 @@ object RoundtripSpec extends ZIOHttpSpec {
string: String,
strings: Chunk[String] = Chunk("defaultString"),
)
implicit val paramsSchema: Schema[Params] = DeriveSchema.gen[Params]
implicit val paramsSchema: Schema[Params] = DeriveSchema.gen[Params]

def spec: Spec[Any, Any] =
suite("RoundtripSpec")(
Expand Down Expand Up @@ -420,7 +420,7 @@ object RoundtripSpec extends ZIOHttpSpec {
executorLayer = ZLayer(ZIO.serviceWith[Client](makeExecutor(_, port)))

cause <- ZIO
.serviceWithZIO[EndpointExecutor] { executor =>
.serviceWithZIO[EndpointExecutor[Any, Unit]] { executor =>
executor.apply(endpointWithAnotherSignature.apply(42))
}
.provideSome[Client with Scope](executorLayer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ object ServerSentEventEndpointSpec extends ZIOSpecDefault {
def locator(port: Int): EndpointLocator = EndpointLocator.fromURL(url"http://localhost:$port")

private val invocation
: Invocation[Unit, Unit, ZNothing, ZStream[Any, Nothing, ServerSentEvent[String]], AuthType.None, Unit] =
: Invocation[Unit, Unit, ZNothing, ZStream[Any, Nothing, ServerSentEvent[String]], AuthType.None] =
sseEndpoint(())

def client(port: Int): ZIO[Scope, Throwable, Chunk[ServerSentEvent[String]]] =
Expand Down Expand Up @@ -74,7 +74,7 @@ object ServerSentEventEndpointSpec extends ZIOSpecDefault {
def locator(port: Int): EndpointLocator = EndpointLocator.fromURL(url"http://localhost:$port")

private val invocation
: Invocation[Unit, Unit, ZNothing, ZStream[Any, Nothing, ServerSentEvent[Payload]], AuthType.None, Unit] =
: Invocation[Unit, Unit, ZNothing, ZStream[Any, Nothing, ServerSentEvent[Payload]], AuthType.None] =
sseEndpoint(())

def client(port: Int): ZIO[Scope, Throwable, Chunk[ServerSentEvent[Payload]]] =
Expand Down
124 changes: 51 additions & 73 deletions zio-http/shared/src/main/scala/zio/http/endpoint/Endpoint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,94 +85,76 @@ final case class Endpoint[PathInput, Input, Err, Output, Auth <: AuthType](
self.copy(input = input) -> condition
}

def apply[AuthInput <: authType.ClientRequirement](auth: AuthInput)(implicit
ev: Input <:< Unit,
): Invocation[PathInput, Input, Err, Output, Auth, AuthInput] =
Invocation(self.asInstanceOf[Endpoint.WithAuthInput[PathInput, Input, Err, Output, Auth, AuthInput]], auth)

def apply[AuthInput](input: AuthInput)(implicit
ev: Auth <:< AuthType.None,
combine: Combiner.WithOut[Input, authType.ClientRequirement, AuthInput],
): Invocation[PathInput, Input, Err, Output, Auth, AuthInput] =
Invocation(self.asInstanceOf[Endpoint.WithAuthInput[PathInput, Input, Err, Output, Auth, AuthInput]], input)

def apply[AuthInput, A, B](a: A, b: B)(implicit
combiner: Combiner.WithOut[Input, authType.ClientRequirement, AuthInput],
ev: (A, B) <:< AuthInput,
): Invocation[PathInput, Input, Err, Output, Auth, AuthInput] =
Invocation(self.asInstanceOf[Endpoint.WithAuthInput[PathInput, Input, Err, Output, Auth, AuthInput]], ev((a, b)))

def apply[AuthInput, A, B, C](a: A, b: B, c: C)(implicit
combiner: Combiner.WithOut[Input, authType.ClientRequirement, AuthInput],
ev: (A, B, C) <:< AuthInput,
): Invocation[PathInput, Input, Err, Output, Auth, AuthInput] =
Invocation(self.asInstanceOf[Endpoint.WithAuthInput[PathInput, Input, Err, Output, Auth, AuthInput]], ev((a, b, c)))

def apply[AuthInput, A, B, C, D](a: A, b: B, c: C, d: D)(implicit
combiner: Combiner.WithOut[Input, authType.ClientRequirement, AuthInput],
ev: (A, B, C, D) <:< AuthInput,
): Invocation[PathInput, Input, Err, Output, Auth, AuthInput] =
def apply(input: Input): Invocation[PathInput, Input, Err, Output, Auth] =
Invocation(self, input)

def apply[A, B](a: A, b: B)(implicit
ev: (A, B) <:< Input,
): Invocation[PathInput, Input, Err, Output, Auth] =
Invocation(self, ev((a, b)))

def apply[A, B, C](a: A, b: B, c: C)(implicit
ev: (A, B, C) <:< Input,
): Invocation[PathInput, Input, Err, Output, Auth] =
Invocation(self, ev((a, b, c)))

def apply[A, B, C, D](a: A, b: B, c: C, d: D)(implicit
ev: (A, B, C, D) <:< Input,
): Invocation[PathInput, Input, Err, Output, Auth] =
Invocation(
self.asInstanceOf[Endpoint.WithAuthInput[PathInput, Input, Err, Output, Auth, AuthInput]],
self,
ev((a, b, c, d)),
)

def apply[AuthInput, A, B, C, D, E](a: A, b: B, c: C, d: D, e: E)(implicit
combiner: Combiner.WithOut[Input, authType.ClientRequirement, AuthInput],
ev: (A, B, C, D, E) <:< AuthInput,
): Invocation[PathInput, Input, Err, Output, Auth, AuthInput] =
def apply[A, B, C, D, E](a: A, b: B, c: C, d: D, e: E)(implicit
ev: (A, B, C, D, E) <:< Input,
): Invocation[PathInput, Input, Err, Output, Auth] =
Invocation(
self.asInstanceOf[Endpoint.WithAuthInput[PathInput, Input, Err, Output, Auth, AuthInput]],
self,
ev((a, b, c, d, e)),
)

def apply[AuthInput, A, B, C, D, E, F](a: A, b: B, c: C, d: D, e: E, f: F)(implicit
combiner: Combiner.WithOut[Input, authType.ClientRequirement, AuthInput],
ev: (A, B, C, D, E, F) <:< AuthInput,
): Invocation[PathInput, Input, Err, Output, Auth, AuthInput] =
def apply[A, B, C, D, E, F](a: A, b: B, c: C, d: D, e: E, f: F)(implicit
ev: (A, B, C, D, E, F) <:< Input,
): Invocation[PathInput, Input, Err, Output, Auth] =
Invocation(
self.asInstanceOf[Endpoint.WithAuthInput[PathInput, Input, Err, Output, Auth, AuthInput]],
self,
ev((a, b, c, d, e, f)),
)

def apply[AuthInput, A, B, C, D, E, F, G](a: A, b: B, c: C, d: D, e: E, f: F, g: G)(implicit
combiner: Combiner.WithOut[Input, authType.ClientRequirement, AuthInput],
ev: (A, B, C, D, E, F, G) <:< AuthInput,
): Invocation[PathInput, Input, Err, Output, Auth, AuthInput] =
def apply[A, B, C, D, E, F, G](a: A, b: B, c: C, d: D, e: E, f: F, g: G)(implicit
ev: (A, B, C, D, E, F, G) <:< Input,
): Invocation[PathInput, Input, Err, Output, Auth] =
Invocation(
self.asInstanceOf[Endpoint.WithAuthInput[PathInput, Input, Err, Output, Auth, AuthInput]],
self,
ev((a, b, c, d, e, f, g)),
)

def apply[AuthInput, A, B, C, D, E, F, G, H](a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H)(implicit
combiner: Combiner.WithOut[Input, authType.ClientRequirement, AuthInput],
ev: (A, B, C, D, E, F, G, H) <:< AuthInput,
): Invocation[PathInput, Input, Err, Output, Auth, AuthInput] =
def apply[A, B, C, D, E, F, G, H](a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H)(implicit
ev: (A, B, C, D, E, F, G, H) <:< Input,
): Invocation[PathInput, Input, Err, Output, Auth] =
Invocation(
self.asInstanceOf[Endpoint.WithAuthInput[PathInput, Input, Err, Output, Auth, AuthInput]],
self,
ev((a, b, c, d, e, f, g, h)),
)

def apply[AuthInput, A, B, C, D, E, F, G, H, I](a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I)(implicit
combiner: Combiner.WithOut[Input, authType.ClientRequirement, AuthInput],
ev: (A, B, C, D, E, F, G, H, I) <:< AuthInput,
): Invocation[PathInput, Input, Err, Output, Auth, AuthInput] =
def apply[A, B, C, D, E, F, G, H, I](a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I)(implicit
ev: (A, B, C, D, E, F, G, H, I) <:< Input,
): Invocation[PathInput, Input, Err, Output, Auth] =
Invocation(
self.asInstanceOf[Endpoint.WithAuthInput[PathInput, Input, Err, Output, Auth, AuthInput]],
self,
ev((a, b, c, d, e, f, g, h, i)),
)

def apply[AuthInput, A, B, C, D, E, F, G, H, I, J](a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J)(
implicit
combiner: Combiner.WithOut[Input, authType.ClientRequirement, AuthInput],
ev: (A, B, C, D, E, F, G, H, I, J) <:< AuthInput,
): Invocation[PathInput, Input, Err, Output, Auth, AuthInput] =
def apply[A, B, C, D, E, F, G, H, I, J](a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J)(implicit
ev: (A, B, C, D, E, F, G, H, I, J) <:< Input,
): Invocation[PathInput, Input, Err, Output, Auth] =
Invocation(
self.asInstanceOf[Endpoint.WithAuthInput[PathInput, Input, Err, Output, Auth, AuthInput]],
self,
ev((a, b, c, d, e, f, g, h, i, j)),
)

def apply[AuthInput, A, B, C, D, E, F, G, H, I, J, K](
def apply[A, B, C, D, E, F, G, H, I, J, K](
a: A,
b: B,
c: C,
Expand All @@ -185,15 +167,14 @@ final case class Endpoint[PathInput, Input, Err, Output, Auth <: AuthType](
j: J,
k: K,
)(implicit
combiner: Combiner.WithOut[Input, authType.ClientRequirement, AuthInput],
ev: (A, B, C, D, E, F, G, H, I, J, K) <:< AuthInput,
): Invocation[PathInput, Input, Err, Output, Auth, AuthInput] =
ev: (A, B, C, D, E, F, G, H, I, J, K) <:< Input,
): Invocation[PathInput, Input, Err, Output, Auth] =
Invocation(
self.asInstanceOf[Endpoint.WithAuthInput[PathInput, Input, Err, Output, Auth, AuthInput]],
self,
ev((a, b, c, d, e, f, g, h, i, j, k)),
)

def apply[AuthInput, A, B, C, D, E, F, G, H, I, J, K, L](
def apply[A, B, C, D, E, F, G, H, I, J, K, L](
a: A,
b: B,
c: C,
Expand All @@ -207,11 +188,10 @@ final case class Endpoint[PathInput, Input, Err, Output, Auth <: AuthType](
k: K,
l: L,
)(implicit
combiner: Combiner.WithOut[Input, authType.ClientRequirement, AuthInput],
ev: (A, B, C, D, E, F, G, H, I, J, K, L) <:< AuthInput,
): Invocation[PathInput, Input, Err, Output, Auth, AuthInput] =
ev: (A, B, C, D, E, F, G, H, I, J, K, L) <:< Input,
): Invocation[PathInput, Input, Err, Output, Auth] =
Invocation(
self.asInstanceOf[Endpoint.WithAuthInput[PathInput, Input, Err, Output, Auth, AuthInput]],
self,
ev((a, b, c, d, e, f, g, h, i, j, k, l)),
)

Expand Down Expand Up @@ -859,15 +839,13 @@ final case class Endpoint[PathInput, Input, Err, Output, Auth <: AuthType](
}

object Endpoint {
type WithAuthInput[PathInput, Input, Err, Output, Auth <: AuthType, AuthInput] =
Endpoint[PathInput, Input, Err, Output, Auth] { type AuthedInput = AuthInput }

/**
* Constructs an endpoint for a route pattern.
*/
def apply[Input](
route: RoutePattern[Input],
): Endpoint.WithAuthInput[Input, Input, ZNothing, ZNothing, AuthType.None, Unit] =
): Endpoint[Input, Input, ZNothing, ZNothing, AuthType.None] =
Endpoint(
route,
route.toHttpCodec,
Expand All @@ -876,7 +854,7 @@ object Endpoint {
HttpContentCodec.responseErrorCodec,
Doc.empty,
AuthType.None,
).asInstanceOf[Endpoint.WithAuthInput[Input, Input, ZNothing, ZNothing, AuthType.None, Unit]]
)

@nowarn("msg=type parameter .* defined")
final case class OutErrors[PathInput, Input, Err, Output, Auth <: AuthType, Err2](
Expand Down
Loading

0 comments on commit a8b432d

Please sign in to comment.