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

Strange api transformation behaviour #41

Open
wookievx opened this issue Jan 2, 2019 · 1 comment
Open

Strange api transformation behaviour #41

wookievx opened this issue Jan 2, 2019 · 1 comment
Labels
bug Something isn't working

Comments

@wookievx
Copy link

wookievx commented Jan 2, 2019

Recently i encountered very strange bug, that was very hard to pinpoint. I will provide example (maybe not minimal but this exact combination causes the failure, in this case UUID as param type and Server.Match element) that should reproduce on version 0.2.0.
I have the following endpoint definition:

val Api = := :> Segment[UUID]("param") :> Server.Match[String]("headers") :> ReqBody[Json, TypeA] :> Put[Json, TypeB]

Now i work with it as always, so i define serialization/deserialization mechanism for request/response, have to define ValueExtractor for UUID and then derive endpoint from it and mount it (using http4s) as backend (i wrote custom integration with the newest version but it is exposing the same types as the standard one):

val endpoint = derive[F](Api).from(func)
val sm = ServerManager(BlazeServerBuilder[F], "0.0.0.0", 8080)
mount(sm, endpoint)

The following code does not compile resulting with compiler error like the following:
could not find implicit value for parameter executor: typedapi.server.EndpointExecutor.Aux[Req,typedapi.shared.SegmentInput :: typedapi.shared.ServerHeaderMatchInput :: shapeless.HNil,String("param") :: String("headers") :: Symbol with shapeless.tag.Tagged[String("body")] with shapeless.labelled.KeyTag[typedapi.dsl.MT.application/json.type,Symbol with shapeless.tag.Tagged[String("body")]] :: shapeless.HNil,java.util.UUID :: scala.collection.immutable.Map[String,String] :: TypeA :: shapeless.HNil,typedapi.shared.PutWithBodyCall,this.Out,F,TypeB,Resp]

I started digging into this error and what i found out is that somehow this.Out is infered to the wrong type by the compiler, or something like that because when i wrote the following custom http4s executor, the same endpoint compiled :

trait SimpleExecutor[R, VIn <: HList, Rout, F[_], FOut, Out] {
  def execute(req: R, eReq: EndpointRequest, endpoint: Endpoint[_, _, VIn, _, Rout, F, FOut]): Either[ExtractionError, Out]
}

//instance very similar to the default http4s executor instance
implicit def noReqBodySimple[VIn <: HList, ROut, F[_], FOut](implicit
    encoder: EntityEncoder[F, FOut],
    ME: Effect[F]
  ): SimpleExecutor[Request[F], VIn, ROut, F, FOut, F[Response[F]]] = ???

//with body instance
implicit def withReqBodySimple[VIn <: HList, ROut <: HList, Bd, F[_], FOut](implicit
    encoder: EntityEncoder[F, FOut],
    ME: Effect[F],
    decoder: EntityDecoder[F, Bd],
    _prepend: Prepend[ROut, Bd :: HNil]
  ): SimpleExecutor[Request[F], VIn, (BodyType[Bd], ROut), F, FOut, F[Response[F]]] = ???

//mounting function, again analogous
def mountHttp4s[VIn <: HList, ROut, M <: MethodType, F[_], FOut](
    server: ServerManager[BlazeServerBuilder[F]],
    endpoint: Endpoint[_, _, VIn, M, ROut, F, FOut]
  )(implicit
    executor: SimpleExecutor[Request[F], VIn, ROut, F, FOut, F[Response[F]]],
    mounting: MountEndpoints.Aux[BlazeServerBuilder[F], Request[F], F[Response[F]], Resource[F, Server[F]]]
  ): Resource[F, Server[F]] = ???

The most important thing i changed is that i erased the information that Rout is equal to VIn and simply casted the value when needed (assuming that it would be equal anyway which only made sense).
Now using mountHttp4s code compiles and runs but what is happening is that Rout is actually a reversal of VIn so i get the following error message when trying to invoke this endpoint:
scala.collection.immutable.Map$EmptyMap$ cannot be cast to java.util.UUID
I checked the original definition of executor for http4s and did not found any part which "reversed" input argument.

I am really puzzled here because the issue seems to be non-existent when using Get method (standard mount works great), it's not only request body issue because for example Delete also fails to compile (and fails at runtime using my special Executor implementation)

@wookievx
Copy link
Author

wookievx commented Jan 2, 2019

On the side note, i think that all this type noise is not necessary when it comes down to executor, it does only need to know that Endpoint accepts hlist of arguments of type VIn and that it may take request body as well. This is what i tried to achieve in my simplified implementation.

@pheymann pheymann added the bug Something isn't working label May 22, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants