scoped-sttp
scoped-sttp provides a sttp loging backend via log4cats and a scoped backend allowing you to pass scoped variables to be used as http headers in sttp calls.
Logging
Example
For some client wrapper
import sttp.client3.*
import sttp.client3.asynchttpclient.cats.AsyncHttpClientCatsBackend
class MyRepo[F[_]: Async]:
val backend: F[Sttpbackend[F, Any]] = AsyncHttpClientCatsBackend[F]()
We can add logging
import sttp.client3.*
import sttp.client3.asynchttpclient.cats.AsyncHttpClientCatsBackend
import org.typelevel.log4cats.*
import is.ashley.scoped.sttp.logging.Log4CatsLoggingBackend
import is.ashley.scoped.{ScopeToString, given}
class MyRepo[F[_]: Transactional: Logger: Async]:
val backend: F[Sttpbackend[F, Any]] =
AsyncHttpClientCatsBackend[F]().map { backend => Log4CatsLoggingBackend(backend) }
Now using Transactional from the example for Scoped and a log4cats logger wrapped with a ScopedLogger in scope (via Logger)
we now have TransactionIds being logged in sttps internal logs (requests going out etc)
Scoped backend
The scoped backend allows us to add headers to the outgoing requests depending on values in scope
Example
It can be used like the following
import sttp.client3.*
import sttp.client3.asynchttpclient.cats.AsyncHttpClientCatsBackend
import org.typelevel.log4cats.*
import is.ashley.scoped.sttp.logging.Log4CatsLoggingBackend
import is.ashley.scoped.{ScopeToString, given}
class MyRepo[F[_]: Transactional: Logger: Async]:
val backend: F[Sttpbackend[F, Any]] =
AsyncHttpClientCatsBackend[F]().map { backend =>
ScopedRequestBackend(backend, mapping = Map("x-transaction-id" -> ScopeToString[F, Option[TransactionId]]))
}
Which will add the x-transaction-id header to the outgoing output if it is set.
Both backends can be used together or standalone.