Skip to content

Commit

Permalink
review
Browse files Browse the repository at this point in the history
  • Loading branch information
sergiuszkierat committed Jan 8, 2025
1 parent 7d9c2ad commit d9205e0
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ trait VertxCatsServerInterpreter[F[_]] extends CommonServerInterpreter with Vert
): Router => Route = { router =>
val routeDef = extractRouteDefinition(e.endpoint)
val readStreamCompatible = fs2ReadStreamCompatible(vertxCatsServerOptions)
optionsRoute(e)(router, routeDef).foreach(_.handler(endpointHandler(e, readStreamCompatible)))
optionsRouteIfCORSDefined(e)(router, routeDef, vertxFutureServerOptions)
.foreach(_.handler(endpointHandler(e, readStreamCompatible)))
mountWithDefaultHandlers(e)(router, routeDef, vertxCatsServerOptions)
.handler(endpointHandler(e, readStreamCompatible))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ trait VertxFutureServerInterpreter extends CommonServerInterpreter with VertxErr
*/
def route[A, U, I, E, O](e: ServerEndpoint[VertxStreams with WebSockets, Future]): Router => Route = { router =>
val routeDef = extractRouteDefinition(e.endpoint)
optionsRoute(e)(router, routeDef).foreach(_.handler(endpointHandler(e)))
optionsRouteIfCORSDefined(e)(router, routeDef, vertxFutureServerOptions)
.foreach(_.handler(endpointHandler(e)))
mountWithDefaultHandlers(e)(router, routeDef, vertxFutureServerOptions)
.handler(endpointHandler(e))
}
Expand All @@ -40,7 +41,8 @@ trait VertxFutureServerInterpreter extends CommonServerInterpreter with VertxErr
*/
def blockingRoute(e: ServerEndpoint[VertxStreams with WebSockets, Future]): Router => Route = { router =>
val routeDef = extractRouteDefinition(e.endpoint)
optionsRoute(e)(router, routeDef).foreach(_.handler(endpointHandler(e)))
optionsRouteIfCORSDefined(e)(router, routeDef, vertxFutureServerOptions)
.foreach(_.handler(endpointHandler(e)))
mountWithDefaultHandlers(e)(router, routeDef, vertxFutureServerOptions)
.blockingHandler(endpointHandler(e))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,45 @@
package sttp.tapir.server.vertx.interpreters

import io.vertx.core.http.HttpMethod._
import io.vertx.ext.web.{Route, Router}
import sttp.model.Method.HEAD
import sttp.tapir.server.ServerEndpoint
import sttp.tapir.server.interceptor.Interceptor
import sttp.tapir.server.interceptor.cors.CORSInterceptor
import sttp.tapir.server.vertx.VertxServerOptions
import sttp.tapir.server.vertx.handlers.attachDefaultHandlers
import sttp.tapir.server.vertx.routing.PathMapping.{RouteDefinition, createOptionsRoute, createRoute}
import sttp.tapir.server.vertx.routing.PathMapping.{RouteDefinition, createRoute}

trait CommonServerInterpreter {
protected def optionsRoute[C, F[_]](e: ServerEndpoint[C, F])(router: Router, routeDef: RouteDefinition): Option[Route] =
createOptionsRoute(router, routeDef)

/** Checks if a CORS interceptor is defined in the server options and creates an OPTIONS route if it is.
*
* Vert.x will signal a 405 error if a route matches the path, but doesn’t match the HTTP Method. So if CORS is defined, we additionally
* register OPTIONS route which accepts the preflight requests.
*
* @return
* An optional Route. If a CORS interceptor is defined, an OPTIONS route is created and returned. Otherwise, None is returned.
*/
protected def optionsRouteIfCORSDefined[C, F[_]](
e: ServerEndpoint[C, F]
)(router: Router, routeDef: RouteDefinition, serverOptions: VertxServerOptions[F]): Option[Route] = {
def isCORSInterceptorDefined[F[_]](interceptors: List[Interceptor[F]]): Boolean = {
interceptors.collectFirst { case ci: CORSInterceptor[F] => ci }.nonEmpty
}

def createOptionsRoute(router: Router, route: RouteDefinition): Option[Route] =
route match {
case (Some(method), path) if Set(GET, HEAD, POST, PUT, DELETE).contains(method) =>
Some(router.options(path))
case (None, path) => Some(router.options(path))
case _ => None
}

if (isCORSInterceptorDefined(serverOptions.interceptors)) {
createOptionsRoute(router, routeDef)
} else
None
}

protected def mountWithDefaultHandlers[C, F[_]](e: ServerEndpoint[C, F])(
router: Router,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@ object PathMapping {
case (None, path) => router.route(path)
}

private[vertx] def createOptionsRoute(router: Router, route: RouteDefinition): Option[Route] =
route match {
case (Some(method), path) if Set(GET, HEAD, POST, PUT, DELETE).contains(method) =>
Some(router.options(path))
case (None, path) => Some(router.options(path))
case _ => None
}

/** Extracts the route definition from the endpoint inputs
* @param endpoint
* a Tapir endpoint
Expand All @@ -58,5 +50,4 @@ object PathMapping {
.mkString
if (path.isEmpty) "/*" else path
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ trait VertxZioServerInterpreter[R] extends CommonServerInterpreter with VertxErr
runtime: Runtime[R & R2]
): Router => Route = { router =>
val routeDef = extractRouteDefinition(e.endpoint)
optionsRoute(e)(router, routeDef).foreach(_.handler(endpointHandler(e)))
optionsRouteIfCORSDefined(e)(router, routeDef, vertxFutureServerOptions)
.foreach(_.handler(endpointHandler(e)))
mountWithDefaultHandlers(e.widen)(router, routeDef, vertxZioServerOptions)
.handler(endpointHandler(e))
}
Expand Down

0 comments on commit d9205e0

Please sign in to comment.