From 46475ba67aaa4258cb3a9999b07889bf1038d923 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 4 Feb 2026 22:55:30 +0100 Subject: [PATCH] refactor/(http4s): add API version matching to resource doc resolution - Extract API version from request path to enable version-specific routing - Add apiVersion comparison in ResourceDocMatcher to match docs by version - Refactor Http4sTestServer logger initialization to use explicit Logger instance - Remove pending markers from integration tests now that version matching is fixed - Enable previously failing route matching tests for v5.0.0 and v7.0.0 endpoints - Fixes 404 errors caused by missing API version validation in resource doc lookup --- .../code/api/util/http4s/Http4sSupport.scala | 17 ++++++++--------- .../src/test/scala/code/Http4sTestServer.scala | 6 +++--- .../Http4sServerIntegrationTest.scala | 5 ----- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/http4s/Http4sSupport.scala b/obp-api/src/main/scala/code/api/util/http4s/Http4sSupport.scala index f231ba002..dcf98de1e 100644 --- a/obp-api/src/main/scala/code/api/util/http4s/Http4sSupport.scala +++ b/obp-api/src/main/scala/code/api/util/http4s/Http4sSupport.scala @@ -1,18 +1,13 @@ package code.api.util.http4s import cats.effect._ -import code.api.APIFailureNewStyle import code.api.util.APIUtil.ResourceDoc -import code.api.util.ErrorMessages._ import code.api.util.CallContext -import com.openbankproject.commons.model.{Bank, BankAccount, BankId, AccountId, ViewId, BankIdAccountId, CounterpartyTrait, User, View} -import net.liftweb.common.{Box, Empty, Full, Failure => LiftFailure} +import com.openbankproject.commons.model.{Bank, User} +import net.liftweb.common.{Box, Empty, Full} import net.liftweb.http.provider.HTTPParam -import net.liftweb.json.{Extraction, compactRender} -import net.liftweb.json.JsonDSL._ import org.http4s._ import org.http4s.dsl.io._ -import org.http4s.headers.`Content-Type` import org.typelevel.ci.CIString import org.typelevel.vault.Key @@ -91,8 +86,8 @@ object Http4sRequestAttributes { * - Ok response creation */ object EndpointHelpers { - import net.liftweb.json.{Extraction, Formats} import net.liftweb.json.JsonAST.prettyRender + import net.liftweb.json.{Extraction, Formats} /** * Execute Future-based business logic and return JSON response. @@ -343,10 +338,14 @@ object ResourceDocMatcher { resourceDocs: ArrayBuffer[ResourceDoc] ): Option[ResourceDoc] = { val pathString = path.renderString + // Extract API version from path (e.g., "v5.0.0" from "/obp/v5.0.0/banks") + val apiVersion = pathString.split("/").filter(_.nonEmpty).drop(1).headOption.getOrElse("") // Strip the API prefix (/obp/vX.X.X) from the path for matching val strippedPath = apiPrefixPattern.replaceFirstIn(pathString, "") resourceDocs.find { doc => - doc.requestVerb.equalsIgnoreCase(verb) && matchesUrlTemplate(strippedPath, doc.requestUrl) + doc.requestVerb.equalsIgnoreCase(verb) && + doc.implementedInApiVersion.toString == apiVersion && + matchesUrlTemplate(strippedPath, doc.requestUrl) } } diff --git a/obp-api/src/test/scala/code/Http4sTestServer.scala b/obp-api/src/test/scala/code/Http4sTestServer.scala index 818cbff64..66a96906f 100644 --- a/obp-api/src/test/scala/code/Http4sTestServer.scala +++ b/obp-api/src/test/scala/code/Http4sTestServer.scala @@ -6,9 +6,7 @@ import code.api.util.APIUtil import code.api.util.http4s.Http4sApp import com.comcast.ip4s._ import net.liftweb.common.Logger -import org.http4s._ import org.http4s.ember.server._ -import org.http4s.implicits._ import scala.concurrent.duration._ @@ -26,7 +24,9 @@ import scala.concurrent.duration._ * val http4sServer = Http4sTestServer * val baseUrl = s"http://${http4sServer.host}:${http4sServer.port}" */ -object Http4sTestServer extends Logger { +object Http4sTestServer { + + private val logger = Logger("code.Http4sTestServer") val host = "127.0.0.1" val port = APIUtil.getPropsAsIntValue("http4s.test.port", 8087) diff --git a/obp-api/src/test/scala/code/api/http4sbridge/Http4sServerIntegrationTest.scala b/obp-api/src/test/scala/code/api/http4sbridge/Http4sServerIntegrationTest.scala index d75ece6f2..2674fad88 100644 --- a/obp-api/src/test/scala/code/api/http4sbridge/Http4sServerIntegrationTest.scala +++ b/obp-api/src/test/scala/code/api/http4sbridge/Http4sServerIntegrationTest.scala @@ -140,7 +140,6 @@ class Http4sServerIntegrationTest extends ServerSetup with DefaultUsers { feature("HTTP4S v7.0.0 Native Endpoints") { scenario("GET /obp/v7.0.0/root returns API info", Http4sServerIntegrationTag) { - pending // TODO: Investigate route matching issue - returns 404 When("We request the root endpoint") val (status, body) = makeHttp4sGetRequest("/obp/v7.0.0/root") @@ -154,7 +153,6 @@ class Http4sServerIntegrationTest extends ServerSetup with DefaultUsers { } scenario("GET /obp/v7.0.0/banks returns banks list", Http4sServerIntegrationTag) { - pending // TODO: Investigate route matching issue - returns 404 When("We request banks list") val (status, body) = makeHttp4sGetRequest("/obp/v7.0.0/banks") @@ -225,7 +223,6 @@ class Http4sServerIntegrationTest extends ServerSetup with DefaultUsers { } scenario("GET /obp/v5.0.0/banks/BANK_ID returns specific bank", Http4sServerIntegrationTag) { - pending // TODO: Investigate route matching issue - returns 404 When("We request a specific bank") val (status, body) = makeHttp4sGetRequest("/obp/v5.0.0/banks/gh.29.de") @@ -238,7 +235,6 @@ class Http4sServerIntegrationTest extends ServerSetup with DefaultUsers { } scenario("GET /obp/v5.0.0/banks/BANK_ID/products returns products", Http4sServerIntegrationTag) { - pending // TODO: Investigate route matching issue - returns 404 When("We request products for a bank") val (status, body) = makeHttp4sGetRequest("/obp/v5.0.0/banks/gh.29.de/products") @@ -251,7 +247,6 @@ class Http4sServerIntegrationTest extends ServerSetup with DefaultUsers { } scenario("GET /obp/v5.0.0/banks/BANK_ID/products/PRODUCT_CODE returns specific product", Http4sServerIntegrationTag) { - pending // TODO: Investigate route matching issue - returns 404 When("We request a specific product") // First get a product code from the products list val (_, productsBody) = makeHttp4sGetRequest("/obp/v5.0.0/banks/gh.29.de/products")