Skip to content

[BUG] RejectHandler doesn't works for Vertx web server #4870

@geny200

Description

@geny200

Tapir version: 1.11.49

Scala version: 2.13.1

Describe the bug

tapir reject handler doesn't works for Vertx web server

How to reproduce?

//> using scala 2.13.16
//> using dep org.typelevel::cats-effect:3.6.3
//> using dep com.softwaremill.sttp.tapir::tapir-vertx-server-cats:1.11.49
//> using dep com.softwaremill.sttp.tapir::tapir-http4s-server:1.11.49
//> using dep org.http4s::http4s-ember-server:0.23.32

import cats.effect._
import cats.effect.std.Dispatcher
import com.comcast.ip4s.Port
import io.vertx.core.Vertx
import io.vertx.ext.web.Router
import org.http4s.ember.server.EmberServerBuilder
import sttp.model.StatusCode
import sttp.tapir._
import sttp.tapir.server.ServerEndpoint
import sttp.tapir.server.http4s.{Http4sServerInterpreter, Http4sServerOptions}
import sttp.tapir.server.interceptor.CustomiseInterceptors
import sttp.tapir.server.interceptor.reject.DefaultRejectHandler
import sttp.tapir.server.model.ValuedEndpointOutput
import sttp.tapir.server.vertx.cats.VertxCatsServerInterpreter._
import sttp.tapir.server.vertx.cats.{VertxCatsServerInterpreter, VertxCatsServerOptions}

object App extends IOApp {
  private val responseEndpoint: ServerEndpoint[Any, IO] =
    endpoint
      .get
      .in("response")
      .in(query[String]("key"))
      .out(plainBody[String])
      .serverLogicSuccessPure(req => s"Response: $req")

  private val okEndpoint: ServerEndpoint[Any, IO] =
    endpoint
      .get
      .in("ok")
      .out(plainBody[String])
      .serverLogicSuccessPure(_ => "OK")

  private val endpoints: List[ServerEndpoint[Any, IO]] = List(responseEndpoint, okEndpoint)

  private def addNotFoundHandler[O]: CustomiseInterceptors[IO, O] => CustomiseInterceptors[IO, O] =
    _
      .rejectHandler(
        DefaultRejectHandler[IO](
          (sc: StatusCode, m: String) => ValuedEndpointOutput(statusCode.and(stringBody), (sc, m)),
          Some((StatusCode.Ok, "Custom Not Found Response"))
        )
      )

  def runAsVertx: IO[Nothing] =
    Dispatcher.parallel[IO].flatMap { dispatcher =>
      Resource
        .make(
          IO.delay {
            val vertx  = Vertx.vertx()
            val server = vertx.createHttpServer()
            val router = Router.router(vertx)

            val options =
              addNotFoundHandler(VertxCatsServerOptions.customiseInterceptors[IO](dispatcher))
                .options

            endpoints.foreach(VertxCatsServerInterpreter[IO](options).route(_)(router))
            server.requestHandler(router).listen(8080)
          }.flatMap(_.asF[IO])
        ) { server =>
          IO.delay(server.close).flatMap(_.asF[IO].void)
        }
    }
      .use(_ => IO.println("Server started on port 8080") >> IO.never)

  def runAsHttp4s: IO[Nothing] = {
    val options =
      addNotFoundHandler(Http4sServerOptions.customiseInterceptors[IO])
        .options

    EmberServerBuilder
      .default[IO]
      .withHttpApp(Http4sServerInterpreter[IO](options).toRoutes(endpoints).orNotFound)
      .withPort(Port.fromInt(8080).get)
      .build
      .use(_ => IO.println("Server started on port 8080") >> IO.never)
  }

  override def run(args: List[String]): IO[ExitCode] = runAsVertx // runAsHttp4s

}

First run with runAsVertx, second run with runAsHttp4s. Then call:

curl http://localhost:8080/something
  • With runAsVertx , I got 404 response (default vertx response, but I expects 200 with Custom Not Found Response):
    <html><body><h1>Resource not found</h1></body></html>
    
  • With runAsHttp4s , I got 200 response (as expected):
    Custom Not Found Response
    

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions