Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,5 @@ coursier
metals.sbt
obp-http4s-runner/src/main/resources/git.properties
test-results
untracked_files/
untracked_files/
obp-http4s-runner/dependency-reduced-pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import code.api.v4_0_0.{APIMethods400, OBPAPI4_0_0}
import code.api.v5_0_0.OBPAPI5_0_0
import code.api.v5_1_0.OBPAPI5_1_0
import code.api.v6_0_0.OBPAPI6_0_0
import code.api.berlin.group.ConstantsBG
import code.apicollectionendpoint.MappedApiCollectionEndpointsProvider
import code.util.Helper
import code.util.Helper.{MdcLoggable, ObpS, SILENCE_IS_GOLDEN}
Expand Down Expand Up @@ -122,6 +123,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth

val resourceDocs = requestedApiVersion match {
case ApiVersion.v7_0_0 => code.api.v7_0_0.Http4s700.resourceDocs
case ConstantsBG.`berlinGroupVersion2` => code.api.berlin.group.v2.Http4sBGv2.resourceDocs
case ApiVersion.v6_0_0 => OBPAPI6_0_0.allResourceDocs
case ApiVersion.v5_1_0 => OBPAPI5_1_0.allResourceDocs
case ApiVersion.v5_0_0 => OBPAPI5_0_0.allResourceDocs
Expand All @@ -144,6 +146,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth

val versionRoutes = requestedApiVersion match {
case ApiVersion.v7_0_0 => Nil
case ConstantsBG.`berlinGroupVersion2` => Nil
case ApiVersion.v6_0_0 => OBPAPI6_0_0.routes
case ApiVersion.v5_1_0 => OBPAPI5_1_0.routes
case ApiVersion.v5_0_0 => OBPAPI5_0_0.routes
Expand Down Expand Up @@ -172,6 +175,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
// Only return the resource docs that have available routes
val activeResourceDocs = requestedApiVersion match {
case ApiVersion.v7_0_0 => resourceDocs
case ConstantsBG.`berlinGroupVersion2` => resourceDocs
case _ => resourceDocs.filter(rd => versionRoutesClasses.contains(rd.partialFunction.getClass))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ object ConstantsBG {
case Full(props) => berlinGroupV13.copy(apiShortVersion = props)
case _ => berlinGroupV13
}
val berlinGroupVersion2: ScannedApiVersion = ScannedApiVersion("berlin-group", "BG", "v2")
object SigningBasketsStatus extends Enumeration {
type SigningBasketsStatus = Value
// Only the codes
Expand Down
31 changes: 31 additions & 0 deletions obp-api/src/main/scala/code/api/berlin/group/v2/Http4sBGv2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package code.api.berlin.group.v2

import cats.data.{Kleisli, OptionT}
import cats.effect._
import code.api.berlin.group.ConstantsBG
import code.api.util.APIUtil.ResourceDoc
import code.api.util.http4s.ResourceDocMiddleware
import code.util.Helper.MdcLoggable
import org.http4s._

import scala.collection.mutable.ArrayBuffer

object Http4sBGv2 extends MdcLoggable {

type HttpF[A] = OptionT[IO, A]

val implementedInApiVersion = ConstantsBG.berlinGroupVersion2

val resourceDocs: ArrayBuffer[ResourceDoc] =
Http4sBGv2AIS.resourceDocs ++
Http4sBGv2PIS.resourceDocs ++
Http4sBGv2PIIS.resourceDocs

val allRoutes: HttpRoutes[IO] = Kleisli[HttpF, Request[IO], Response[IO]] { req =>
Http4sBGv2AIS.routes(req)
.orElse(Http4sBGv2PIS.routes(req))
.orElse(Http4sBGv2PIIS.routes(req))
}

val wrappedRoutes: HttpRoutes[IO] = ResourceDocMiddleware.apply(resourceDocs)(allRoutes)
}
243 changes: 243 additions & 0 deletions obp-api/src/main/scala/code/api/berlin/group/v2/Http4sBGv2AIS.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
package code.api.berlin.group.v2

import cats.data.{Kleisli, OptionT}
import cats.effect._
import code.api.berlin.group.ConstantsBG
import code.api.util.APIUtil.{EmptyBody, ResourceDoc}
import code.api.util.ApiTag._
import code.api.util.ErrorMessages._
import code.api.util.CustomJsonFormats
import code.util.Helper.MdcLoggable
import com.github.dwickern.macros.NameOf.nameOf
import net.liftweb.json.JsonAST.prettyRender
import net.liftweb.json.{Extraction, Formats}
import org.http4s._
import org.http4s.dsl.io._

import scala.collection.mutable.ArrayBuffer
import scala.language.implicitConversions

object Http4sBGv2AIS extends MdcLoggable {

type HttpF[A] = OptionT[IO, A]

implicit val formats: Formats = CustomJsonFormats.formats
implicit def convertAnyToJsonString(any: Any): String = prettyRender(Extraction.decompose(any))

val implementedInApiVersion = ConstantsBG.berlinGroupVersion2
val resourceDocs = ArrayBuffer[ResourceDoc]()

val bgV2Prefix = Root / ConstantsBG.berlinGroupVersion2.urlPrefix / ConstantsBG.berlinGroupVersion2.apiShortVersion

// ── GET /v2/accounts ──────────────────────────────────────────────

resourceDocs += ResourceDoc(
null,
implementedInApiVersion,
nameOf(getAccountList),
"GET",
"/accounts",
"Read Account List",
"Returns a list of bank accounts.",
EmptyBody,
JSONFactory_BERLIN_GROUP_v2.mockAccountList,
List(UnknownError),
apiTagPSD2AIS :: apiTagBerlinGroupM :: Nil,
http4sPartialFunction = Some(getAccountList)
)

val getAccountList: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ GET -> `bgV2Prefix` / "accounts" =>
Ok(convertAnyToJsonString(JSONFactory_BERLIN_GROUP_v2.mockAccountList))
}

// ── GET /v2/accounts/{account-id} ─────────────────────────────────

resourceDocs += ResourceDoc(
null,
implementedInApiVersion,
nameOf(getAccountDetails),
"GET",
"/accounts/ACCOUNT_ID",
"Read Account Details",
"Returns details of a single bank account.",
EmptyBody,
JSONFactory_BERLIN_GROUP_v2.mockAccountDetails("ACCOUNT_ID"),
List(UnknownError),
apiTagPSD2AIS :: apiTagBerlinGroupM :: Nil,
http4sPartialFunction = Some(getAccountDetails)
)

val getAccountDetails: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ GET -> `bgV2Prefix` / "accounts" / accountId if !accountId.contains("/") =>
Ok(convertAnyToJsonString(JSONFactory_BERLIN_GROUP_v2.mockAccountDetails(accountId)))
}

// ── GET /v2/accounts/{account-id}/balances ────────────────────────

resourceDocs += ResourceDoc(
null,
implementedInApiVersion,
nameOf(getAccountBalances),
"GET",
"/accounts/ACCOUNT_ID/balances",
"Read Balance",
"Returns balances of a given account.",
EmptyBody,
JSONFactory_BERLIN_GROUP_v2.mockBalances("ACCOUNT_ID"),
List(UnknownError),
apiTagPSD2AIS :: apiTagBerlinGroupM :: Nil,
http4sPartialFunction = Some(getAccountBalances)
)

val getAccountBalances: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ GET -> `bgV2Prefix` / "accounts" / accountId / "balances" =>
Ok(convertAnyToJsonString(JSONFactory_BERLIN_GROUP_v2.mockBalances(accountId)))
}

// ── GET /v2/accounts/{account-id}/transactions ────────────────────

resourceDocs += ResourceDoc(
null,
implementedInApiVersion,
nameOf(getTransactionList),
"GET",
"/accounts/ACCOUNT_ID/transactions",
"Read Transaction List",
"Returns transactions of a given account.",
EmptyBody,
JSONFactory_BERLIN_GROUP_v2.mockTransactions("ACCOUNT_ID"),
List(UnknownError),
apiTagPSD2AIS :: apiTagBerlinGroupM :: Nil,
http4sPartialFunction = Some(getTransactionList)
)

val getTransactionList: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ GET -> `bgV2Prefix` / "accounts" / accountId / "transactions" =>
Ok(convertAnyToJsonString(JSONFactory_BERLIN_GROUP_v2.mockTransactions(accountId)))
}

// ── GET /v2/accounts/{account-id}/transactions/{transactionId} ────

resourceDocs += ResourceDoc(
null,
implementedInApiVersion,
nameOf(getTransactionDetails),
"GET",
"/accounts/ACCOUNT_ID/transactions/TRANSACTION_ID",
"Read Transaction Details",
"Returns details of a single transaction.",
EmptyBody,
JSONFactory_BERLIN_GROUP_v2.mockTransactionDetails("ACCOUNT_ID", "TRANSACTION_ID"),
List(UnknownError),
apiTagPSD2AIS :: apiTagBerlinGroupM :: Nil,
http4sPartialFunction = Some(getTransactionDetails)
)

val getTransactionDetails: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ GET -> `bgV2Prefix` / "accounts" / accountId / "transactions" / transactionId =>
Ok(convertAnyToJsonString(JSONFactory_BERLIN_GROUP_v2.mockTransactionDetails(accountId, transactionId)))
}

// ── GET /v2/card-accounts ─────────────────────────────────────────

resourceDocs += ResourceDoc(
null,
implementedInApiVersion,
nameOf(getCardAccountList),
"GET",
"/card-accounts",
"Read Card Account List",
"Returns a list of card accounts.",
EmptyBody,
JSONFactory_BERLIN_GROUP_v2.mockCardAccountList,
List(UnknownError),
apiTagPSD2AIS :: apiTagBerlinGroupM :: Nil,
http4sPartialFunction = Some(getCardAccountList)
)

val getCardAccountList: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ GET -> `bgV2Prefix` / "card-accounts" =>
Ok(convertAnyToJsonString(JSONFactory_BERLIN_GROUP_v2.mockCardAccountList))
}

// ── GET /v2/card-accounts/{account-id} ────────────────────────────

resourceDocs += ResourceDoc(
null,
implementedInApiVersion,
nameOf(getCardAccountDetails),
"GET",
"/card-accounts/ACCOUNT_ID",
"Read Card Account Details",
"Returns details of a single card account.",
EmptyBody,
JSONFactory_BERLIN_GROUP_v2.mockCardAccountDetails("ACCOUNT_ID"),
List(UnknownError),
apiTagPSD2AIS :: apiTagBerlinGroupM :: Nil,
http4sPartialFunction = Some(getCardAccountDetails)
)

val getCardAccountDetails: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ GET -> `bgV2Prefix` / "card-accounts" / accountId if !accountId.contains("/") =>
Ok(convertAnyToJsonString(JSONFactory_BERLIN_GROUP_v2.mockCardAccountDetails(accountId)))
}

// ── GET /v2/card-accounts/{account-id}/balances ───────────────────

resourceDocs += ResourceDoc(
null,
implementedInApiVersion,
nameOf(getCardAccountBalances),
"GET",
"/card-accounts/ACCOUNT_ID/balances",
"Read Card Account Balances",
"Returns balances of a given card account.",
EmptyBody,
JSONFactory_BERLIN_GROUP_v2.mockCardAccountBalances("ACCOUNT_ID"),
List(UnknownError),
apiTagPSD2AIS :: apiTagBerlinGroupM :: Nil,
http4sPartialFunction = Some(getCardAccountBalances)
)

val getCardAccountBalances: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ GET -> `bgV2Prefix` / "card-accounts" / accountId / "balances" =>
Ok(convertAnyToJsonString(JSONFactory_BERLIN_GROUP_v2.mockCardAccountBalances(accountId)))
}

// ── GET /v2/card-accounts/{account-id}/transactions ───────────────

resourceDocs += ResourceDoc(
null,
implementedInApiVersion,
nameOf(getCardAccountTransactionList),
"GET",
"/card-accounts/ACCOUNT_ID/transactions",
"Read Card Account Transaction List",
"Returns transactions of a given card account.",
EmptyBody,
JSONFactory_BERLIN_GROUP_v2.mockCardAccountTransactions("ACCOUNT_ID"),
List(UnknownError),
apiTagPSD2AIS :: apiTagBerlinGroupM :: Nil,
http4sPartialFunction = Some(getCardAccountTransactionList)
)

val getCardAccountTransactionList: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ GET -> `bgV2Prefix` / "card-accounts" / accountId / "transactions" =>
Ok(convertAnyToJsonString(JSONFactory_BERLIN_GROUP_v2.mockCardAccountTransactions(accountId)))
}

// ── Combined routes ───────────────────────────────────────────────

val routes: HttpRoutes[IO] = Kleisli[HttpF, Request[IO], Response[IO]] { req =>
getAccountList(req)
.orElse(getAccountBalances(req))
.orElse(getTransactionDetails(req))
.orElse(getTransactionList(req))
.orElse(getAccountDetails(req))
.orElse(getCardAccountList(req))
.orElse(getCardAccountBalances(req))
.orElse(getCardAccountTransactionList(req))
.orElse(getCardAccountDetails(req))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package code.api.berlin.group.v2

import cats.data.{Kleisli, OptionT}
import cats.effect._
import code.api.berlin.group.ConstantsBG
import code.api.util.APIUtil.{EmptyBody, ResourceDoc}
import code.api.util.ApiTag._
import code.api.util.ErrorMessages._
import code.api.util.CustomJsonFormats
import code.util.Helper.MdcLoggable
import com.github.dwickern.macros.NameOf.nameOf
import net.liftweb.json.JsonAST.prettyRender
import net.liftweb.json.{Extraction, Formats}
import org.http4s._
import org.http4s.dsl.io._

import scala.collection.mutable.ArrayBuffer
import scala.language.implicitConversions

object Http4sBGv2PIIS extends MdcLoggable {

type HttpF[A] = OptionT[IO, A]

implicit val formats: Formats = CustomJsonFormats.formats
implicit def convertAnyToJsonString(any: Any): String = prettyRender(Extraction.decompose(any))

val implementedInApiVersion = ConstantsBG.berlinGroupVersion2
val resourceDocs = ArrayBuffer[ResourceDoc]()

val bgV2Prefix = Root / ConstantsBG.berlinGroupVersion2.urlPrefix / ConstantsBG.berlinGroupVersion2.apiShortVersion

// ── POST /v2/funds-confirmations ──────────────────────────────────

resourceDocs += ResourceDoc(
null,
implementedInApiVersion,
nameOf(postConfirmationOfFunds),
"POST",
"/funds-confirmations",
"Confirmation of Funds Request",
"Checks whether a specific amount is available on an account.",
EmptyBody,
JSONFactory_BERLIN_GROUP_v2.mockFundsConfirmation,
List(UnknownError),
apiTagPSD2PIIS :: apiTagBerlinGroupM :: Nil,
http4sPartialFunction = Some(postConfirmationOfFunds)
)

val postConfirmationOfFunds: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ POST -> `bgV2Prefix` / "funds-confirmations" =>
Ok(convertAnyToJsonString(JSONFactory_BERLIN_GROUP_v2.mockFundsConfirmation))
}

// ── Combined routes ───────────────────────────────────────────────

val routes: HttpRoutes[IO] = Kleisli[HttpF, Request[IO], Response[IO]] { req =>
postConfirmationOfFunds(req)
}
}
Loading
Loading