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

Attaching HandlerAspect to a Routes object with mulitple dependencies does not work (using Scala2) #3112

Closed
kurgansoft opened this issue Sep 7, 2024 · 8 comments · Fixed by #3128
Labels
💎 Bounty bug Something isn't working 💰 Rewarded

Comments

@kurgansoft
Copy link

The operator '@@' is used to attach a HandlerAspect to a Routes object.

It is working fine if applying results in a Routes object with no dependencies.

If the result is a Routes object with one dependency, it still works, but that dependency needs to be declared explicitly, like:
.@@[Int]

However if the result is a Routes object with multiple dependencies, it won't work even if we declare those dependencies explicitly.

Using scala 3 everything works as expected, and the type does not need to be declared explicitly either.

Example code to reproduce the issue:

//> using dep dev.zio::zio-http::3.0.0-RC10
//> using scala 2.13.14

import zio.http.codec.{HttpCodec, StatusCodec}
import zio.http.endpoint.{AuthType, Endpoint}
import zio.http.{HandlerAspect, Header, Route, RoutePattern, Routes, withContext}
import zio._

object Issue extends App {
  val effectWithNoDependency: IO[Nothing, String] = for {
    _ <- ZIO.log("executing effect with no dependency")
  } yield "hardcodedResult - effectWithNoDependency"

  val effectWithOneDependency: ZIO[Int, Nothing, String] = for {
    magicNumber <- ZIO.service[Int]
    _ <- ZIO.log(s"executing effect with one dependency; magic number is $magicNumber")
  } yield "hardcodedResult - effectWithOneDependency"

  val effectWithTwoDependency: ZIO[Int & Long, Nothing, String] = for {
    magicNumber <- ZIO.service[Int]
    magicNumber2 <- ZIO.service[Long]
    _ <- ZIO.log(s"executing effect with two dependency; magic numbers are: $magicNumber and $magicNumber2")
  } yield "hardcodedResult - effectWithTwoDependency"

  val authContext: HandlerAspect[Any, String] = HandlerAspect.customAuthProviding[String] { request =>
    {
      request.headers.get(Header.Authorization).flatMap {
        case Header.Authorization.Basic(uname, secret) if uname.reverse == secret.value.mkString =>
          Some(uname)
        case _ =>
          None
      }
    }
  }

  val endpoint = Endpoint(RoutePattern.GET / "route1")
    .outCodec[String](StatusCodec.Ok ++ HttpCodec.content[String])
    .auth(AuthType.Basic)

  val route1: Route[String, Nothing] = endpoint.implement((_: Unit) =>
    withContext((username: String) => ZIO.log(s"username is $username")) *>
      effectWithNoDependency
  )

  // The authContext eliminates the String dependency
  val routes1: Routes[Any, Nothing] = Routes(route1) @@ authContext

  val route2: Route[Int & String, Nothing] = endpoint.implement((_: Unit) =>
    withContext((username: String) => ZIO.log(s"username is $username")) *>
      effectWithOneDependency
  )

  // The authContext eliminates the String dependency, so only the Int dependency remains
  // But what remains - it has to be declared explicitly
  val routes2: Routes[Int, Nothing] = Routes(route2).@@[Int](authContext)

  val route3: Route[Int & Long & String, Nothing] = endpoint.implement((_: Unit) =>
    withContext((username: String) => ZIO.log(s"username is $username")) *>
      effectWithTwoDependency
  )

  // Like in routes2 we would like to eliminate the String dependency so only Int and Long would remain.
  // However, the below gives this compilation error:
  // "A Tag may not contain an intersection type, yet have provided: Int with Long"
  val routes3: Routes[Int & Long, Nothing] = Routes(route3).@@[Int & Long](authContext)
}
@kurgansoft kurgansoft added the bug Something isn't working label Sep 7, 2024
@jdegoes
Copy link
Member

jdegoes commented Sep 10, 2024

/bounty $150 for fix and test

Copy link

algora-pbc bot commented Sep 10, 2024

💎 $150 bounty • ZIO

Steps to solve:

  1. Start working: Comment /attempt #3112 with your implementation plan
  2. Submit work: Create a pull request including /claim #3112 in the PR body to claim the bounty
  3. Receive payment: 100% of the bounty is received 2-5 days post-reward. Make sure you are eligible for payouts

Thank you for contributing to zio/zio-http!

Add a bountyShare on socials

Attempt Started (GMT+0) Solution
🟢 @stdthoth Sep 10, 2024, 3:38:30 PM WIP
🟢 @asr2003 Sep 11, 2024, 6:11:34 AM WIP
🟢 @pawelsadlo #3128

@stdthoth
Copy link

stdthoth commented Sep 10, 2024

/attempt #3112

@asr2003
Copy link
Contributor

asr2003 commented Sep 11, 2024

/attempt #3112

Algora profile Completed bounties Tech Active attempts Options
@asr2003    2 ZIO bounties
+ 2 bounties from 2 projects
JavaScript, Go,
HTML & more
﹟9101
Cancel attempt

Copy link

algora-pbc bot commented Sep 11, 2024

Note

The user @stdthoth is already attempting to complete issue #3112 and claim the bounty. We recommend checking in on @stdthoth's progress, and potentially collaborating, before starting a new solution.

Copy link

algora-pbc bot commented Sep 11, 2024

💡 @pawelsadlo submitted a pull request that claims the bounty. You can visit your bounty board to reward.

Copy link

algora-pbc bot commented Sep 11, 2024

🎉🎈 @pawelsadlo has been awarded $150! 🎈🎊

@frekw
Copy link
Contributor

frekw commented Oct 8, 2024

I'm still running into this with zio-http 3.0.1, needing to resort to the previous workaround:

type Env = UploadService with AuthInterceptor

val withViewer = Middleware.customAuthProvidingZIO[AuthInterceptor, Viewer](req =>
  (for {
    interceptor <- ZIO.service[AuthInterceptor]
    viewer <- interceptor.intercept(req)
  } yield Some(viewer))

val routes = API.upload.@@[Env](withViewer)

or otherwise it fails with:

Cannot prove that Env0 with Viewer <:< Viewer with UploadService with Viewer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💎 Bounty bug Something isn't working 💰 Rewarded
Projects
None yet
5 participants