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

Recursive type in endpoint input causes misleading error #181

Closed
kubukoz opened this issue Apr 13, 2022 · 1 comment
Closed

Recursive type in endpoint input causes misleading error #181

kubukoz opened this issue Apr 13, 2022 · 1 comment
Labels
bug Something isn't working

Comments

@kubukoz
Copy link
Member

kubukoz commented Apr 13, 2022

Tested on 0.12.11.

For this spec:

namespace demo.smithy

use smithy4s.api#simpleRestJson

@simpleRestJson
service DemoService {
  version: "0.0.1",
  operations: [CreateHello],
}

@http(method: "PUT", uri: "/subscriptions")
@idempotent
operation CreateHello {
  input: HelloInput,
  output: HelloOutput,
}

structure HelloInput {
  @httpPayload
  @required
  hello: Hello
}

structure HelloOutput {

}

structure Hello {
  @required
  id: String,
  // recursive call
  next: Hello
}

For this Scala:

import smithy4s.http4s.SimpleRestJsonBuilder
import demo.smithy.DemoService
import org.http4s.client.Client
import org.http4s.HttpApp
import cats.effect.IO
import org.http4s.Uri

object Main extends App {

  SimpleRestJsonBuilder(DemoService).client(
    HttpApp.notFound[IO],
    Uri.unsafeFromString("http://localhost")
  )
}

Run sbt run.

If you remove the recursive call in the Hello shape, it works. If you keep it:

[info] running Main 
[error] java.lang.RuntimeException: Operation CreateHello is not bound to http semantics
[error]         at scala.sys.package$.error(package.scala:30)
[error]         at smithy4s.http4s.SmithyHttp4sReverseRouter$$anon$1.$anonfun$apply$1(SmithyHttp4sReverseRouter.scala:57)
[error]         at scala.Option.getOrElse(Option.scala:189)
[error]         at smithy4s.http4s.SmithyHttp4sReverseRouter$$anon$1.apply(SmithyHttp4sReverseRouter.scala:56)
[error]         at smithy4s.http4s.SmithyHttp4sReverseRouter$$anon$1.apply(SmithyHttp4sReverseRouter.scala:43)
[error]         at smithy4s.Transformation$$anon$3.$anonfun$map$1(Transformation.scala:61)
[error]         at scala.collection.immutable.List.foreach(List.scala:431)
[error]         at smithy4s.Transformation$$anon$3.<init>(Transformation.scala:59)
[error]         at smithy4s.Transformation.precompute(Transformation.scala:56)
[error]         at smithy4s.Transformation.precompute$(Transformation.scala:53)
[error]         at smithy4s.http4s.SmithyHttp4sReverseRouter$$anon$1.precompute(SmithyHttp4sReverseRouter.scala:43)
[error]         at smithy4s.http4s.SmithyHttp4sReverseRouter.<init>(SmithyHttp4sReverseRouter.scala:60)
[error]         at smithy4s.http4s.SimpleProtocolBuilder$ServiceBuilder.client(SimpleProtocolBuilder.scala:82)
[error]         at Main$.delayedEndpoint$Main$1(Main.scala:10)
[error]         at Main$delayedInit$body.apply(Main.scala:8)
[error]         at scala.Function0.apply$mcV$sp(Function0.scala:39)
[error]         at scala.Function0.apply$mcV$sp$(Function0.scala:39)
[error]         at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:17)
[error]         at scala.App.$anonfun$main$1$adapted(App.scala:80)
[error]         at scala.collection.immutable.List.foreach(List.scala:431)
[error]         at scala.App.main(App.scala:80)
[error]         at scala.App.main$(App.scala:78)
[error]         at Main$.main(Main.scala:8)
[error]         at Main.main(Main.scala)
[error]         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error]         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error]         at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error]         at java.base/java.lang.reflect.Method.invoke(Method.java:566)
[error] stack trace is suppressed; run last Compile / run for the full output
[error] (Compile / run) Operation CreateHello is not bound to http semantics
[error] Total time: 1 s, completed Apr 13, 2022, 7:28:31 PM
@kubukoz
Copy link
Member Author

kubukoz commented Apr 13, 2022

Generated before recursion:

//Hello.scala
package demo.smithy

import smithy4s.syntax._

case class Hello(id: String)
object Hello extends smithy4s.ShapeTag.Companion[Hello] {
  val id: smithy4s.ShapeId = smithy4s.ShapeId("demo.smithy", "Hello")

  val hints : smithy4s.Hints = smithy4s.Hints(
    id,
  )

  val schema: smithy4s.Schema[Hello] = struct(
    string.required[Hello]("id", _.id).withHints(smithy.api.Required()),
  ){
    Hello.apply
  }.withHints(hints)
  implicit val staticSchema : schematic.Static[smithy4s.Schema[Hello]] = schematic.Static(schema)
}

//HelloInput.scala
package demo.smithy

import smithy4s.syntax._

case class HelloInput(hello: Hello)
object HelloInput extends smithy4s.ShapeTag.Companion[HelloInput] {
  val id: smithy4s.ShapeId = smithy4s.ShapeId("demo.smithy", "HelloInput")

  val hints : smithy4s.Hints = smithy4s.Hints(
    id,
  )

  val schema: smithy4s.Schema[HelloInput] = struct(
    Hello.schema.required[HelloInput]("hello", _.hello).withHints(smithy.api.Required(), smithy.api.HttpPayload()),
  ){
    HelloInput.apply
  }.withHints(hints)
  implicit val staticSchema : schematic.Static[smithy4s.Schema[HelloInput]] = schematic.Static(schema)
}

After recursion:

//Hello.scala
package demo.smithy

import smithy4s.syntax._

case class Hello(id: String, next: Option[Hello] = None)
object Hello extends smithy4s.ShapeTag.Companion[Hello] {
  val id: smithy4s.ShapeId = smithy4s.ShapeId("demo.smithy", "Hello")

  val hints : smithy4s.Hints = smithy4s.Hints(
    id,
  )

  val schema: smithy4s.Schema[Hello] = recursive(struct(
    string.required[Hello]("id", _.id).withHints(smithy.api.Required()),
    Hello.schema.optional[Hello]("next", _.next),
  ){
    Hello.apply
  }.withHints(hints))
  implicit val staticSchema : schematic.Static[smithy4s.Schema[Hello]] = schematic.Static(schema)
}

//HelloInput.scala
package demo.smithy

import smithy4s.syntax._

case class HelloInput(hello: Hello)
object HelloInput extends smithy4s.ShapeTag.Companion[HelloInput] {
  val id: smithy4s.ShapeId = smithy4s.ShapeId("demo.smithy", "HelloInput")

  val hints : smithy4s.Hints = smithy4s.Hints(
    id,
  )

  val schema: smithy4s.Schema[HelloInput] = recursive(struct(
    Hello.schema.required[HelloInput]("hello", _.hello).withHints(smithy.api.Required(), smithy.api.HttpPayload()),
  ){
    HelloInput.apply
  }.withHints(hints))
  implicit val staticSchema : schematic.Static[smithy4s.Schema[HelloInput]] = schematic.Static(schema)
}

First thing that surprises me is that HelloInput has a recursive(...) there, even though it doesn't actually have recursion on its own.

@kubukoz kubukoz added the bug Something isn't working label Apr 14, 2022
@Baccata Baccata closed this as completed in 81bff5e Jun 1, 2022
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

1 participant