Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
95db087
v4.0.0 retirement (1/2): rewire OBPAPI4_0_0 to Http4s400, drop Lift r…
hongwei1 May 20, 2026
64731e7
fix(v4.0.0): port answerTransactionRequestChallenge and add missing P…
hongwei1 May 20, 2026
0826ea5
refactor(v4.0.0): stub APIMethods400 — all Lift v4 endpoints now live…
hongwei1 May 20, 2026
4284138
test: regenerate frozen_type_meta_data to include createOrUpdateTrans…
hongwei1 May 20, 2026
799ea51
refactor(v5.1.0/v6.0.0): restore nameOf(Implementations4_0_0.xxx) in …
hongwei1 May 20, 2026
7771abd
refactor(v4.0.0): restore nameOf calls for excludeEndpoints and test …
hongwei1 May 20, 2026
ea415eb
Merge remote-tracking branch 'OBP/develop' into develop-obp
hongwei1 May 20, 2026
1d0ff07
feat(v3.1.0): add getObpConnectorLoopback and getMessageDocsSwagger t…
hongwei1 May 20, 2026
6446144
refactor(v3.1.0): rewire OBPAPI3_1_0 to Http4s310, routes=Nil
hongwei1 May 20, 2026
2a2051c
refactor(v3.1.0): stub APIMethods310, add Implementations3_1_0 re-exp…
hongwei1 May 20, 2026
377e56c
fix(v3.1.0): resolve NPE, FrozenClassTest, and SystemViews failures
hongwei1 May 20, 2026
128b841
fix(v3.1.0): fix SystemViews 401/403, ConsentTest 500, CardAttributeT…
hongwei1 May 20, 2026
6efb288
refactor(v3.0.0): retire Lift dispatch layer — rewire OBPAPI3_0_0, pa…
hongwei1 May 20, 2026
b78afa1
refactor(v3.0.0): stub APIMethods300 and CustomAPIMethods300
hongwei1 May 20, 2026
5b3f9f6
fix(v3.0.0): re-export Implementations2_2_0 in OBPAPI3_0_0
hongwei1 May 20, 2026
64379ac
fix(test): use v2.2.0 Lift doc in JSONFactory1_4_0Test technology check
hongwei1 May 20, 2026
fc57a5f
refactor/revert the code and comment them
hongwei1 May 21, 2026
291b924
Merge remote-tracking branch 'Simon/develop' into refactor/removeV300…
hongwei1 May 21, 2026
3d07d35
Merge remote-tracking branch 'OBP/develop' into refactor/removeV300Lift
hongwei1 May 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
case ApiVersion.v6_0_0 => resourceDocs // fully on http4s — no Lift route filter
case ApiVersion.v5_1_0 => resourceDocs // fully on http4s — no Lift route filter
case ApiVersion.v5_0_0 => resourceDocs // fully on http4s — no Lift route filter
case ApiVersion.v4_0_0 => resourceDocs // fully on http4s — no Lift route filter
case ApiVersion.v3_1_0 => resourceDocs // fully on http4s — no Lift route filter
case ApiVersion.v3_0_0 => resourceDocs // fully on http4s — no Lift route filter
case _ => resourceDocs.filter(rd => versionRoutesClasses.contains(rd.partialFunction.getClass))
}

Expand Down
28 changes: 14 additions & 14 deletions obp-api/src/main/scala/code/api/util/http4s/Http4sSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package code.api.util.http4s

import cats.effect._
import code.api.util.APIUtil.{ResourceDoc, getPropsAsBoolValue}
import code.api.util.ErrorMessages.InvalidJsonFormat
import code.api.util.ErrorMessages.{AuthenticatedUserIsRequired, InvalidJsonFormat}
import code.api.util.{AuthHeaderParser, CallContext, RemoteIpUtil, WriteMetricUtil}
import code.util.Helper.MdcLoggable
import com.openbankproject.commons.model.{Bank, BankAccount, CounterpartyTrait, User, View}
Expand Down Expand Up @@ -146,7 +146,7 @@ object Http4sRequestAttributes {
def withUser[A](req: Request[IO])(f: (User, CallContext) => Future[A])(implicit formats: Formats): IO[Response[IO]] = {
implicit val cc: CallContext = req.callContext
val io = for {
user <- IO.fromOption(cc.user.toOption)(new RuntimeException("User not found in CallContext"))
user <- IO.fromOption(cc.user.toOption)(new RuntimeException(AuthenticatedUserIsRequired))
result <- RequestScopeConnection.fromFuture(f(user, cc))
} yield result
io.attempt.flatMap {
Expand Down Expand Up @@ -178,7 +178,7 @@ object Http4sRequestAttributes {
def withUserAndBank[A](req: Request[IO])(f: (User, Bank, CallContext) => Future[A])(implicit formats: Formats): IO[Response[IO]] = {
implicit val cc: CallContext = req.callContext
val io = for {
user <- IO.fromOption(cc.user.toOption)(new RuntimeException("User not found in CallContext"))
user <- IO.fromOption(cc.user.toOption)(new RuntimeException(AuthenticatedUserIsRequired))
bank <- IO.fromOption(cc.bank)(new RuntimeException("Bank not found in CallContext"))
result <- RequestScopeConnection.fromFuture(f(user, bank, cc))
} yield result
Expand Down Expand Up @@ -243,7 +243,7 @@ object Http4sRequestAttributes {
case Left(msg) => ErrorResponseConverter.createErrorResponse(400, msg, cc).flatTap(recordMetric(msg, _))
case Right(body) =>
val io = for {
user <- IO.fromOption(cc.user.toOption)(new RuntimeException("User not found in CallContext"))
user <- IO.fromOption(cc.user.toOption)(new RuntimeException(AuthenticatedUserIsRequired))
result <- RequestScopeConnection.fromFuture(f(user, body, cc))
} yield result
io.attempt.flatMap {
Expand All @@ -263,7 +263,7 @@ object Http4sRequestAttributes {
case Left(msg) => ErrorResponseConverter.createErrorResponse(400, msg, cc).flatTap(recordMetric(msg, _))
case Right(body) =>
val io = for {
user <- IO.fromOption(cc.user.toOption)(new RuntimeException("User not found in CallContext"))
user <- IO.fromOption(cc.user.toOption)(new RuntimeException(AuthenticatedUserIsRequired))
result <- RequestScopeConnection.fromFuture(f(user, body, cc))
} yield result
io.attempt.flatMap {
Expand All @@ -285,7 +285,7 @@ object Http4sRequestAttributes {
case Left(msg) => ErrorResponseConverter.createErrorResponse(400, msg, cc).flatTap(recordMetric(msg, _))
case Right(body) =>
val io = for {
user <- IO.fromOption(cc.user.toOption)(new RuntimeException("User not found in CallContext"))
user <- IO.fromOption(cc.user.toOption)(new RuntimeException(AuthenticatedUserIsRequired))
bank <- IO.fromOption(cc.bank)(new RuntimeException("Bank not found in CallContext"))
result <- RequestScopeConnection.fromFuture(f(user, bank, body, cc))
} yield result
Expand All @@ -306,7 +306,7 @@ object Http4sRequestAttributes {
case Left(msg) => ErrorResponseConverter.createErrorResponse(400, msg, cc).flatTap(recordMetric(msg, _))
case Right(body) =>
val io = for {
user <- IO.fromOption(cc.user.toOption)(new RuntimeException("User not found in CallContext"))
user <- IO.fromOption(cc.user.toOption)(new RuntimeException(AuthenticatedUserIsRequired))
bank <- IO.fromOption(cc.bank)(new RuntimeException("Bank not found in CallContext"))
result <- RequestScopeConnection.fromFuture(f(user, bank, body, cc))
} yield result
Expand All @@ -326,7 +326,7 @@ object Http4sRequestAttributes {
def withBankAccount[A](req: Request[IO])(f: (User, BankAccount, CallContext) => Future[A])(implicit formats: Formats): IO[Response[IO]] = {
implicit val cc: CallContext = req.callContext
val io = for {
user <- IO.fromOption(cc.user.toOption)(new RuntimeException("User not found in CallContext"))
user <- IO.fromOption(cc.user.toOption)(new RuntimeException(AuthenticatedUserIsRequired))
bankAccount <- IO.fromOption(cc.bankAccount)(new RuntimeException("BankAccount not found in CallContext"))
result <- RequestScopeConnection.fromFuture(f(user, bankAccount, cc))
} yield result
Expand All @@ -343,7 +343,7 @@ object Http4sRequestAttributes {
def withViewCreated[A](req: Request[IO])(f: (User, BankAccount, View, CallContext) => Future[A])(implicit formats: Formats): IO[Response[IO]] = {
implicit val cc: CallContext = req.callContext
val io = for {
user <- IO.fromOption(cc.user.toOption)(new RuntimeException("User not found in CallContext"))
user <- IO.fromOption(cc.user.toOption)(new RuntimeException(AuthenticatedUserIsRequired))
bankAccount <- IO.fromOption(cc.bankAccount)(new RuntimeException("BankAccount not found in CallContext"))
view <- IO.fromOption(cc.view)(new RuntimeException("View not found in CallContext"))
result <- RequestScopeConnection.fromFuture(f(user, bankAccount, view, cc))
Expand All @@ -366,7 +366,7 @@ object Http4sRequestAttributes {
case Left(msg) => ErrorResponseConverter.createErrorResponse(400, msg, cc).flatTap(recordMetric(msg, _))
case Right(body) =>
val io = for {
user <- IO.fromOption(cc.user.toOption)(new RuntimeException("User not found in CallContext"))
user <- IO.fromOption(cc.user.toOption)(new RuntimeException(AuthenticatedUserIsRequired))
bankAccount <- IO.fromOption(cc.bankAccount)(new RuntimeException("BankAccount not found in CallContext"))
view <- IO.fromOption(cc.view)(new RuntimeException("View not found in CallContext"))
result <- RequestScopeConnection.fromFuture(f(user, bankAccount, view, body, cc))
Expand All @@ -387,7 +387,7 @@ object Http4sRequestAttributes {
def withView[A](req: Request[IO])(f: (User, BankAccount, View, CallContext) => Future[A])(implicit formats: Formats): IO[Response[IO]] = {
implicit val cc: CallContext = req.callContext
val io = for {
user <- IO.fromOption(cc.user.toOption)(new RuntimeException("User not found in CallContext"))
user <- IO.fromOption(cc.user.toOption)(new RuntimeException(AuthenticatedUserIsRequired))
bankAccount <- IO.fromOption(cc.bankAccount)(new RuntimeException("BankAccount not found in CallContext"))
view <- IO.fromOption(cc.view)(new RuntimeException("View not found in CallContext"))
result <- RequestScopeConnection.fromFuture(f(user, bankAccount, view, cc))
Expand All @@ -405,7 +405,7 @@ object Http4sRequestAttributes {
def withCounterparty[A](req: Request[IO])(f: (User, BankAccount, View, CounterpartyTrait, CallContext) => Future[A])(implicit formats: Formats): IO[Response[IO]] = {
implicit val cc: CallContext = req.callContext
val io = for {
user <- IO.fromOption(cc.user.toOption)(new RuntimeException("User not found in CallContext"))
user <- IO.fromOption(cc.user.toOption)(new RuntimeException(AuthenticatedUserIsRequired))
bankAccount <- IO.fromOption(cc.bankAccount)(new RuntimeException("BankAccount not found in CallContext"))
view <- IO.fromOption(cc.view)(new RuntimeException("View not found in CallContext"))
counterparty <- IO.fromOption(cc.counterparty)(new RuntimeException("Counterparty not found in CallContext"))
Expand Down Expand Up @@ -463,7 +463,7 @@ object Http4sRequestAttributes {
def withUserDelete(req: Request[IO])(f: (User, CallContext) => Future[_]): IO[Response[IO]] = {
implicit val cc: CallContext = req.callContext
val io = for {
user <- IO.fromOption(cc.user.toOption)(new RuntimeException("User not found in CallContext"))
user <- IO.fromOption(cc.user.toOption)(new RuntimeException(AuthenticatedUserIsRequired))
result <- RequestScopeConnection.fromFuture(f(user, cc))
} yield result
io.attempt.flatMap {
Expand All @@ -479,7 +479,7 @@ object Http4sRequestAttributes {
def withUserAndBankDelete(req: Request[IO])(f: (User, Bank, CallContext) => Future[_]): IO[Response[IO]] = {
implicit val cc: CallContext = req.callContext
val io = for {
user <- IO.fromOption(cc.user.toOption)(new RuntimeException("User not found in CallContext"))
user <- IO.fromOption(cc.user.toOption)(new RuntimeException(AuthenticatedUserIsRequired))
bank <- IO.fromOption(cc.bank)(new RuntimeException("Bank not found in CallContext"))
result <- RequestScopeConnection.fromFuture(f(user, bank, cc))
} yield result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,17 @@ object ResourceDocMiddleware extends MdcLoggable {
// No matching ResourceDoc: fallback to original route (NO transaction scope opened).
// Attach the basic CC so req.callContext works in the inner route even without a doc match.
// Carry the cached body forward so the bridge cascade can still read it.
routes.run(reqWithCachedBody.withAttribute(Http4sRequestAttributes.callContextKey, cc))
// Best-effort authentication: populate cc.user from request credentials so that
// withUser/withUserAndBank handlers return 401/403 correctly (e.g. empty path segments
// that bypass ResourceDocMatcher but still match a route pattern).
OptionT.liftF(
IO.fromFuture(IO(APIUtil.anonymousAccess(cc))).map {
case (Full(user), Some(updatedCC)) => reqWithCachedBody.withAttribute(Http4sRequestAttributes.callContextKey, updatedCC.copy(user = Full(user)))
case (Full(user), None) => reqWithCachedBody.withAttribute(Http4sRequestAttributes.callContextKey, cc.copy(user = Full(user)))
case (_, Some(updatedCC)) => reqWithCachedBody.withAttribute(Http4sRequestAttributes.callContextKey, updatedCC)
case _ => reqWithCachedBody.withAttribute(Http4sRequestAttributes.callContextKey, cc)
}.recover { case _ => reqWithCachedBody.withAttribute(Http4sRequestAttributes.callContextKey, cc) }
).flatMap(routes.run)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion obp-api/src/main/scala/code/api/v1_2_1/Http4s121.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2472,5 +2472,5 @@ object Http4s121 {
}
}

val wrappedRoutesV121Services: HttpRoutes[IO] = Implementations1_2_1.allRoutesWithMiddleware
lazy val wrappedRoutesV121Services: HttpRoutes[IO] = Implementations1_2_1.allRoutesWithMiddleware
}
Loading
Loading