Skip to content

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

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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions