Skip to content

Commit 58e42da

Browse files
authored
Merge pull request #2817 from hongwei1/refactor/migrateUKstandard
Refactor/migrate ukstandard
2 parents 3eb41c1 + eeb54a7 commit 58e42da

53 files changed

Lines changed: 20945 additions & 12703 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
189189
case ApiVersion.v1_4_0 => resourceDocs // fully on http4s — no Lift route filter
190190
case ApiVersion.v1_3_0 => resourceDocs // fully on http4s — no Lift route filter
191191
case ApiVersion.`dynamic-entity` => resourceDocs // runtime CRUD now on Http4sDynamicEntity; routes are Nil, skip Lift-route filter
192+
case ApiVersion.ukOpenBankingV20 => resourceDocs // fully on http4s — no Lift route filter
193+
case ApiVersion.ukOpenBankingV31 => resourceDocs // fully on http4s — no Lift route filter
192194
case _ => resourceDocs.filter(rd => versionRoutesClasses.contains(rd.partialFunction.getClass))
193195
}
194196

obp-api/src/main/scala/code/api/UKOpenBanking/v2_0_0/APIMethods_UKOpenBanking_200.scala

Lines changed: 236 additions & 235 deletions
Large diffs are not rendered by default.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package code.api.UKOpenBanking.v2_0_0
2+
3+
import cats.data.{Kleisli, OptionT}
4+
import cats.effect._
5+
import code.api.util.APIUtil.ResourceDoc
6+
import code.api.util.http4s.ResourceDocMiddleware
7+
import code.util.Helper.MdcLoggable
8+
import com.openbankproject.commons.util.ApiVersion
9+
import org.http4s._
10+
11+
import scala.collection.mutable.ArrayBuffer
12+
13+
/**
14+
* UK Open Banking v2.0 — http4s aggregator (mirror of Berlin Group's Http4sBGv2).
15+
*
16+
* Wraps the migrated account-information routes with ResourceDocMiddleware and
17+
* exposes `wrappedRoutes` for Http4sApp. All 5 v2.0 endpoints — including the two
18+
* account-scoped ones (/accounts/ID/balances, /accounts/ID/transactions) — are
19+
* migrated in Http4sUKOBv200AIS. The Lift ScannedApis aggregator
20+
* (OBP_UKOpenBanking_200) registers `routes = Nil`, so no UK v2.0 path is served
21+
* by Lift — nothing falls through to the Lift bridge.
22+
*/
23+
object Http4sUKOBv200 extends MdcLoggable {
24+
25+
type HttpF[A] = OptionT[IO, A]
26+
27+
val implementedInApiVersion: ApiVersion = ApiVersion.ukOpenBankingV20
28+
29+
val resourceDocs: ArrayBuffer[ResourceDoc] =
30+
Http4sUKOBv200AIS.resourceDocs
31+
32+
val allRoutes: HttpRoutes[IO] = Kleisli[HttpF, Request[IO], Response[IO]] { req =>
33+
Http4sUKOBv200AIS.routes(req)
34+
}
35+
36+
val wrappedRoutes: HttpRoutes[IO] = ResourceDocMiddleware.apply(resourceDocs)(allRoutes)
37+
}
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package code.api.UKOpenBanking.v2_0_0
2+
3+
import cats.data.{Kleisli, OptionT}
4+
import cats.effect.IO
5+
import code.api.APIFailureNewStyle
6+
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
7+
import code.api.util.APIUtil.{EmptyBody, ResourceDoc, createQueriesByHttpParams, fullBoxOrException, unboxFull}
8+
import code.api.util.ApiTag._
9+
import code.api.util.CustomJsonFormats
10+
import code.api.util.ErrorMessages.{AuthenticatedUserIsRequired, UnknownError}
11+
import code.api.util.NewStyle
12+
import code.api.util.http4s.Http4sRequestAttributes.EndpointHelpers
13+
import code.api.util.newstyle.ViewNewStyle
14+
import code.model.BankAccountExtended
15+
import code.util.Helper.MdcLoggable
16+
import code.views.Views
17+
import com.github.dwickern.macros.NameOf.nameOf
18+
import com.openbankproject.commons.ExecutionContext.Implicits.global
19+
import com.openbankproject.commons.model.{AccountId, BankIdAccountId}
20+
import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
21+
import net.liftweb.common.Full
22+
import net.liftweb.http.provider.HTTPParam
23+
import net.liftweb.json.Formats
24+
import org.http4s._
25+
import org.http4s.dsl.io._
26+
27+
import scala.collection.mutable.ArrayBuffer
28+
import scala.concurrent.Future
29+
30+
/**
31+
* UK Open Banking v2.0 — account-information endpoints migrated from Lift to http4s.
32+
*
33+
* Faithful migration of all 5 endpoints:
34+
* - getAccountList (/accounts), getAccount (/accounts/ID), getBalances (/balances)
35+
* — list/aggregate endpoints using getBankAccounts + a JSON factory.
36+
* - getAccountBalances (/accounts/ID/balances), getAccountTransactions
37+
* (/accounts/ID/transactions) — account-scoped endpoints; their 3-segment
38+
* patterns are distinct from the 2-segment ones, so http4s route matching
39+
* picks the correct handler.
40+
* No v2.0 endpoint is left on Lift.
41+
*/
42+
object Http4sUKOBv200AIS extends MdcLoggable {
43+
type HttpF[A] = OptionT[IO, A]
44+
implicit val formats: Formats = CustomJsonFormats.formats
45+
val implementedInApiVersion: ScannedApiVersion = ApiVersion.ukOpenBankingV20
46+
val resourceDocs = ArrayBuffer[ResourceDoc]()
47+
val ukV20Prefix = Root / ApiVersion.ukOpenBankingV20.urlPrefix / ApiVersion.ukOpenBankingV20.apiShortVersion
48+
49+
// GET /accounts — list all private accounts of the logged-in user
50+
lazy val getAccountList: HttpRoutes[IO] = HttpRoutes.of[IO] {
51+
case req @ GET -> `ukV20Prefix` / "accounts" =>
52+
EndpointHelpers.withUser(req) { (u, cc) =>
53+
val callContext = Some(cc)
54+
for {
55+
availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u)
56+
(accounts, _) <- NewStyle.function.getBankAccounts(availablePrivateAccounts, callContext)
57+
} yield JSONFactory_UKOpenBanking_200.createAccountsListJSON(accounts)
58+
}
59+
}
60+
resourceDocs += ResourceDoc(
61+
null,
62+
implementedInApiVersion,
63+
nameOf(getAccountList),
64+
"GET",
65+
"/accounts",
66+
"UK Open Banking: Get Account List",
67+
"""Reads a list of bank accounts, with balances where required.""",
68+
EmptyBody,
69+
SwaggerDefinitionsJSON.accountsJsonUKOpenBanking_v200,
70+
List(AuthenticatedUserIsRequired, UnknownError),
71+
List(apiTagUKOpenBanking, apiTagAccount, apiTagPrivateData),
72+
http4sPartialFunction = Some(getAccountList)
73+
)
74+
75+
// GET /accounts/{accountId} — single account
76+
lazy val getAccount: HttpRoutes[IO] = HttpRoutes.of[IO] {
77+
case req @ GET -> `ukV20Prefix` / "accounts" / accountId =>
78+
EndpointHelpers.withUser(req) { (u, cc) =>
79+
val callContext = Some(cc)
80+
for {
81+
availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u).map(_.filter(_.accountId.value == accountId))
82+
(accounts, _) <- NewStyle.function.getBankAccounts(availablePrivateAccounts, callContext)
83+
} yield JSONFactory_UKOpenBanking_200.createAccountJSON(accounts)
84+
}
85+
}
86+
resourceDocs += ResourceDoc(
87+
null,
88+
implementedInApiVersion,
89+
nameOf(getAccount),
90+
"GET",
91+
"/accounts/ACCOUNT_ID",
92+
"UK Open Banking: Get Account",
93+
"""Reads a bank account, with balances where required.""",
94+
EmptyBody,
95+
SwaggerDefinitionsJSON.accountsJsonUKOpenBanking_v200,
96+
List(AuthenticatedUserIsRequired, UnknownError),
97+
List(apiTagUKOpenBanking, apiTagAccount, apiTagPrivateData),
98+
http4sPartialFunction = Some(getAccount)
99+
)
100+
101+
// GET /balances — bulk balances for all private accounts
102+
lazy val getBalances: HttpRoutes[IO] = HttpRoutes.of[IO] {
103+
case req @ GET -> `ukV20Prefix` / "balances" =>
104+
EndpointHelpers.withUser(req) { (u, cc) =>
105+
val callContext = Some(cc)
106+
for {
107+
availablePrivateAccounts <- Views.views.vend.getPrivateBankAccountsFuture(u)
108+
(accounts, _) <- NewStyle.function.getBankAccounts(availablePrivateAccounts, callContext)
109+
} yield JSONFactory_UKOpenBanking_200.createBalancesJSON(accounts)
110+
}
111+
}
112+
resourceDocs += ResourceDoc(
113+
null,
114+
implementedInApiVersion,
115+
nameOf(getBalances),
116+
"GET",
117+
"/balances",
118+
"UK Open Banking: Get Balances",
119+
"""Bulk retrieval of balances for all authorised accounts.""",
120+
EmptyBody,
121+
SwaggerDefinitionsJSON.accountBalancesUKV200,
122+
List(AuthenticatedUserIsRequired, UnknownError),
123+
List(apiTagUKOpenBanking, apiTagAccount, apiTagPrivateData),
124+
http4sPartialFunction = Some(getBalances)
125+
)
126+
127+
// GET /accounts/{accountId}/balances — account-level balances
128+
lazy val getAccountBalances: HttpRoutes[IO] = HttpRoutes.of[IO] {
129+
case req @ GET -> `ukV20Prefix` / "accounts" / accountIdStr / "balances" =>
130+
EndpointHelpers.withUser(req) { (u, cc) =>
131+
for {
132+
(account, _) <- NewStyle.function.getBankAccountByAccountId(AccountId(accountIdStr), Some(cc))
133+
view <- ViewNewStyle.checkOwnerViewAccessAndReturnOwnerView(u, BankIdAccountId(account.bankId, account.accountId), Some(cc))
134+
moderatedAccount <- Future {
135+
BankAccountExtended(account).moderatedBankAccount(view, BankIdAccountId(account.bankId, account.accountId), Full(u), Some(cc))
136+
} map { x => unboxFull(fullBoxOrException(x ~> APIFailureNewStyle(UnknownError, 400, Some(cc.toLight)))) }
137+
} yield JSONFactory_UKOpenBanking_200.createAccountBalanceJSON(moderatedAccount)
138+
}
139+
}
140+
resourceDocs += ResourceDoc(
141+
null,
142+
implementedInApiVersion,
143+
nameOf(getAccountBalances),
144+
"GET",
145+
"/accounts/ACCOUNT_ID/balances",
146+
"UK Open Banking: Get Account Balances",
147+
"""An AISP may retrieve the account balance information resource for a specific AccountId.""",
148+
EmptyBody,
149+
SwaggerDefinitionsJSON.accountBalancesUKV200,
150+
List(AuthenticatedUserIsRequired, UnknownError),
151+
List(apiTagUKOpenBanking, apiTagAccount, apiTagPrivateData),
152+
http4sPartialFunction = Some(getAccountBalances)
153+
)
154+
155+
// GET /accounts/{accountId}/transactions — account-level transactions
156+
lazy val getAccountTransactions: HttpRoutes[IO] = HttpRoutes.of[IO] {
157+
case req @ GET -> `ukV20Prefix` / "accounts" / accountIdStr / "transactions" =>
158+
EndpointHelpers.withUser(req) { (u, cc) =>
159+
for {
160+
(account, _) <- NewStyle.function.getBankAccountByAccountId(AccountId(accountIdStr), Some(cc))
161+
(bank, _) <- NewStyle.function.getBank(account.bankId, Some(cc))
162+
view <- ViewNewStyle.checkOwnerViewAccessAndReturnOwnerView(u, BankIdAccountId(account.bankId, account.accountId), Some(cc))
163+
params <- Future {
164+
createQueriesByHttpParams(req.headers.headers.toList.map(h => HTTPParam(h.name.toString, List(h.value))))
165+
} map { x => unboxFull(fullBoxOrException(x ~> APIFailureNewStyle(UnknownError, 400, Some(cc.toLight)))) }
166+
(transactions, _) <- Future {
167+
BankAccountExtended(account).getModeratedTransactions(bank, Full(u), view, BankIdAccountId(account.bankId, account.accountId), Some(cc), params)
168+
} map { x => unboxFull(fullBoxOrException(x ~> APIFailureNewStyle(UnknownError, 400, Some(cc.toLight)))) }
169+
} yield JSONFactory_UKOpenBanking_200.createTransactionsJson(transactions, Nil)
170+
}
171+
}
172+
resourceDocs += ResourceDoc(
173+
null,
174+
implementedInApiVersion,
175+
nameOf(getAccountTransactions),
176+
"GET",
177+
"/accounts/ACCOUNT_ID/transactions",
178+
"UK Open Banking: Get Account Transactions",
179+
"""Reads account data from a given account addressed by "account-id".""",
180+
EmptyBody,
181+
SwaggerDefinitionsJSON.transactionsJsonUKV200,
182+
List(AuthenticatedUserIsRequired, UnknownError),
183+
List(apiTagUKOpenBanking, apiTagTransaction, apiTagPrivateData),
184+
http4sPartialFunction = Some(getAccountTransactions)
185+
)
186+
187+
val routes: HttpRoutes[IO] = Kleisli[HttpF, Request[IO], Response[IO]] { req =>
188+
getAccountList(req)
189+
.orElse(getAccount(req))
190+
.orElse(getAccountBalances(req))
191+
.orElse(getAccountTransactions(req))
192+
.orElse(getBalances(req))
193+
}
194+
}
Lines changed: 33 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,46 @@
1-
/**
2-
Open Bank Project - API
3-
Copyright (C) 2011-2019, TESOBE GmbH.
4-
5-
This program is free software: you can redistribute it and/or modify
6-
it under the terms of the GNU Affero General Public License as published by
7-
the Free Software Foundation, either version 3 of the License, or
8-
(at your option) any later version.
9-
10-
This program is distributed in the hope that it will be useful,
11-
but WITHOUT ANY WARRANTY; without even the implied warranty of
12-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13-
GNU Affero General Public License for more details.
14-
15-
You should have received a copy of the GNU Affero General Public License
16-
along with this program. If not, see <http://www.gnu.org/licenses/>.
17-
18-
Email: contact@tesobe.com
19-
TESOBE GmbH.
20-
Osloer Strasse 16/17
21-
Berlin 13359, Germany
22-
23-
This product includes software developed at
24-
TESOBE (http://www.tesobe.com/)
25-
26-
*/
271
package code.api.UKOpenBanking.v2_0_0
282

293
import code.api.OBPRestHelper
30-
import code.api.util.APIUtil.{OBPEndpoint, getAllowedEndpoints}
4+
import code.api.util.APIUtil.{OBPEndpoint, ResourceDoc}
315
import code.api.util.ScannedApis
326
import code.util.Helper.MdcLoggable
7+
import com.openbankproject.commons.util.{ApiVersion, ApiVersionStatus, ScannedApiVersion}
338

34-
import scala.collection.immutable.Nil
35-
import code.api.UKOpenBanking.v2_0_0.APIMethods_UKOpenBanking_200._
36-
import com.openbankproject.commons.util.{ApiVersion, ApiVersionStatus}
37-
9+
import scala.collection.mutable.ArrayBuffer
3810

3911
/*
40-
This file defines which endpoints from all the versions are available in v1
12+
* All v2.0 UK Open Banking endpoints have been migrated to Http4sUKOBv200AIS.
13+
* This stub is retained for ScannedApis registration (class-path scanning) and
14+
* so that external callers (APIUtil, SwaggerJSONFactory) that access
15+
* OBP_UKOpenBanking_200.apiVersion / .allResourceDocs continue to compile.
16+
* Routes are served by Http4sUKOBv200.wrappedRoutes in Http4sApp (ahead of the Lift bridge).
4117
*/
18+
object OBP_UKOpenBanking_200 extends OBPRestHelper with MdcLoggable with ScannedApis {
4219

20+
override val apiVersion: ScannedApiVersion = ApiVersion.ukOpenBankingV20
21+
val versionStatus: String = ApiVersionStatus.DRAFT.toString
4322

44-
object OBP_UKOpenBanking_200 extends OBPRestHelper with MdcLoggable with ScannedApis{
45-
46-
override val apiVersion = ApiVersion.ukOpenBankingV20
47-
val versionStatus = ApiVersionStatus.DRAFT.toString
48-
49-
val allEndpoints =
50-
getAccountList ::
51-
getAccountTransactions ::
52-
getAccount ::
53-
getAccountBalances ::
54-
getBalances ::
55-
Nil
56-
57-
override val allResourceDocs = resourceDocs
58-
59-
// Filter the possible endpoints by the disabled / enabled Props settings and add them together
60-
override val routes : List[OBPEndpoint] = getAllowedEndpoints(allEndpoints,resourceDocs)
61-
62-
63-
// Make them available for use!
64-
registerRoutes(routes, allResourceDocs, apiPrefix)
65-
66-
logger.info(s"version $version has been run! There are ${routes.length} routes.")
23+
override val allResourceDocs: ArrayBuffer[ResourceDoc] = Http4sUKOBv200.resourceDocs
6724

25+
override val routes: List[OBPEndpoint] = Nil
6826
}
27+
28+
// ─── Original Lift aggregator (commented out) ────────────────────────────────
29+
//import code.api.UKOpenBanking.v2_0_0.APIMethods_UKOpenBanking_200._
30+
//import scala.collection.immutable.{Nil => immNil}
31+
//import code.api.util.APIUtil.getAllowedEndpoints
32+
//
33+
// val allEndpoints =
34+
// getAccountList ::
35+
// getAccountTransactions ::
36+
// getAccount ::
37+
// getAccountBalances ::
38+
// getBalances ::
39+
// immNil
40+
//
41+
// override val allResourceDocs = resourceDocs
42+
//
43+
// override val routes : List[OBPEndpoint] = getAllowedEndpoints(allEndpoints, resourceDocs)
44+
//
45+
// registerRoutes(routes, allResourceDocs, apiPrefix)
46+
// logger.info(s"version $version has been run! There are ${routes.length} routes.")

0 commit comments

Comments
 (0)