Hello,
Apologies in advance as I’m not too sure how to even phrase my question…
I’m using a RequestInterceptor
to read a correlation id header and set it to a IOLocal
so that it can be added to the MDC when logging, or forwarded to a STTP backend etc. That works great!
Now I haven’t found a way to attach that correlation id into a header for all endpoint responses. Is that possible?
Hope I make sense! Thank you for the help!
adamw
June 21, 2024, 6:32am
2
You should be able to transform the RequestResult
, for example:
package sttp.tapir.examples2
import cats.effect.std.Dispatcher
import cats.effect.{IO, IOApp}
import sttp.model.Header
import sttp.monad.MonadError
import sttp.tapir.server.netty.cats.{NettyCatsServer, NettyCatsServerOptions}
import sttp.tapir._
import sttp.tapir.model.ServerRequest
import sttp.tapir.server.ServerEndpoint
import sttp.tapir.server.interceptor.{EndpointInterceptor, RequestHandler, RequestInterceptor, RequestResult, Responder}
object HelloWorldNettyCatsServer extends IOApp.Simple {
val helloWorldEndpoint: PublicEndpoint[String, Unit, String, Any] =
endpoint.get.in("hello").in(query[String]("name")).out(stringBody)
// Just returning passed name with `Hello, ` prepended
val helloWorldServerEndpoint = helloWorldEndpoint
.serverLogic(name => IO.pure[Either[Unit, String]](Right(s"Hello, $name!")))
// Creating handler for netty bootstrap
override def run = Dispatcher
.parallel[IO]
.map(d =>
NettyCatsServer
.apply(
NettyCatsServerOptions
.default[IO](d)
.appendInterceptor(
new RequestInterceptor[IO] {
override def apply[R, B](responder: Responder[IO, B], requestHandler: EndpointInterceptor[IO] => RequestHandler[IO, R, B])
: RequestHandler[IO, R, B] =
new RequestHandler[IO, R, B] {
override def apply(request: ServerRequest, endpoints: List[ServerEndpoint[R, IO]])(implicit
monad: MonadError[IO]
): IO[RequestResult[B]] = {
val cid = request.header("CID").getOrElse("???")
println(cid)
requestHandler(EndpointInterceptor.noop).apply(request, endpoints).map {
case RequestResult.Response(response) =>
RequestResult.Response(response.addHeaders(List(Header("CID", cid))))
case f: RequestResult.Failure => f
}
}
}
}
)
)
)
.use { server =>
for {
binding <- server.addEndpoint(helloWorldServerEndpoint).start()
result <- IO.never.guarantee(binding.stop())
} yield result
}
}
curl -H "CID: abc" -v "http://localhost:8080/hello?name=adam"
> GET /hello?name=adam HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.6.0
> Accept: */*
> CID: abc
>
< HTTP/1.1 200 OK
< server: tapir/1.10.9
< CID: abc
< Content-Type: text/plain; charset=UTF-8
< content-length: 12
<
* Connection #0 to host localhost left intact
Hello, adam!%
1 Like
Awesome, that’s perfect, thank you!