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
This commit is contained in:
hongwei 2026-02-04 22:55:30 +01:00
parent 71d47ed32f
commit 46475ba67a
3 changed files with 11 additions and 17 deletions

View File

@ -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)
}
}

View File

@ -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)

View File

@ -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")