Since the vertx-rx build is currently broken until the RC3 version is merged, I decided to make a small experiment in Scala 3.
I created an extension method on vertx-web's Router named `reply`, that uses virtual threads:
case class User(first: String, last: String) derives JsonConv
class App extends AbstractVerticle:
override def start(): Unit =
val router = Router.router(vertx)
router.get("/user").reply(getUser)
vertx.createHttpServer()
.requestHandler(router)
.listen(8085)
def getUser(ctx: RoutingContext): User =
User("august", "nagro")
{"first":"august","last":"nagro"}The implementation of `reply` accepts a function from RoutingContext to any T with a `given` (aka implicit) instance of JsonConv[T] available. JsonConv is essentially jackson-databind, but at compile time and supporting Scala 3's typeclass derivation.
trait JsonConv[T]:
/**
* Convert T to a JsonArray, JsonObject, or
* a type that is implicitly considered Json,
* like Int or Map
*/
extension (t: T) def toJson: Any
/**
* Map json to type T. May throw any
* RuntimeException subclass
*/
def fromJson(json: Any): T
And finally, the implementation of reply:
extension (route: Route)
def reply[T](handler: RoutingContext => T)(using jc: JsonConv[T]): Route =
route.respond(ctx =>
val promise = Promise.promise[Any]()
Thread.ofVirtual().start(() =>
try
promise.complete(handler(ctx).toJson)
catch case t: Throwable =>
promise.fail(t)
)
promise.future()
)
I am curious about your thoughts. So far, I've found debugging to be quite nice.
One problem that is immediately apparent is that you still encounter Vertx Future, which needs a blocking `get` method that throws on failure. `result` returns null and does not throw. That can also be added by an extension method, but might be nice to have in the API proper.
I have not tested performance; should I fork the TechEmpower benchmarks or does Vertx have its own set of benchmarks?