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.