mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 11:06:49 +00:00
added _links for dynamic entity CRUD endpoints. + adding GET system
database pool endpoint
This commit is contained in:
parent
b4856ef2ac
commit
3d4660ec0b
@ -406,6 +406,9 @@ object ApiRole extends MdcLoggable{
|
||||
case class CanGetCacheInfo(requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canGetCacheInfo = CanGetCacheInfo()
|
||||
|
||||
case class CanGetDatabasePoolInfo(requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canGetDatabasePoolInfo = CanGetDatabasePoolInfo()
|
||||
|
||||
|
||||
case class CanGetCacheNamespaces(requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canGetCacheNamespaces = CanGetCacheNamespaces()
|
||||
|
||||
@ -30,7 +30,7 @@ import code.api.v5_0_0.{ViewJsonV500, ViewsJsonV500}
|
||||
import code.api.v5_1_0.{JSONFactory510, PostCustomerLegalNameJsonV510}
|
||||
import code.api.dynamic.entity.helper.{DynamicEntityHelper, DynamicEntityInfo}
|
||||
import code.api.v6_0_0.JSONFactory600.{AddUserToGroupResponseJsonV600, DynamicEntityDiagnosticsJsonV600, DynamicEntityIssueJsonV600, GroupEntitlementJsonV600, GroupEntitlementsJsonV600, GroupJsonV600, GroupsJsonV600, PostGroupJsonV600, PostGroupMembershipJsonV600, PostResetPasswordUrlJsonV600, PutGroupJsonV600, ReferenceTypeJsonV600, ReferenceTypesJsonV600, ResetPasswordUrlJsonV600, RoleWithEntitlementCountJsonV600, RolesWithEntitlementCountsJsonV600, ScannedApiVersionJsonV600, UpdateViewJsonV600, UserGroupMembershipJsonV600, UserGroupMembershipsJsonV600, ValidateUserEmailJsonV600, ValidateUserEmailResponseJsonV600, ViewJsonV600, ViewPermissionJsonV600, ViewPermissionsJsonV600, ViewsJsonV600, createAbacRuleJsonV600, createAbacRulesJsonV600, createActiveRateLimitsJsonV600, createCallLimitJsonV600, createRedisCallCountersJson}
|
||||
import code.api.v6_0_0.{AbacRuleJsonV600, AbacRuleResultJsonV600, AbacRulesJsonV600, CacheConfigJsonV600, CacheInfoJsonV600, CacheNamespaceInfoJsonV600, CreateAbacRuleJsonV600, CreateDynamicEntityRequestJsonV600, CurrentConsumerJsonV600, DynamicEntityDefinitionJsonV600, DynamicEntityDefinitionWithCountJsonV600, DynamicEntitiesWithCountJsonV600, ExecuteAbacRuleJsonV600, InMemoryCacheStatusJsonV600, MyDynamicEntitiesJsonV600, RedisCacheStatusJsonV600, UpdateAbacRuleJsonV600, UpdateDynamicEntityRequestJsonV600}
|
||||
import code.api.v6_0_0.{AbacRuleJsonV600, AbacRuleResultJsonV600, AbacRulesJsonV600, CacheConfigJsonV600, CacheInfoJsonV600, CacheNamespaceInfoJsonV600, CreateAbacRuleJsonV600, CreateDynamicEntityRequestJsonV600, CurrentConsumerJsonV600, DynamicEntityDefinitionJsonV600, DynamicEntityDefinitionWithCountJsonV600, DynamicEntitiesWithCountJsonV600, DynamicEntityLinksJsonV600, ExecuteAbacRuleJsonV600, InMemoryCacheStatusJsonV600, MyDynamicEntitiesJsonV600, RedisCacheStatusJsonV600, RelatedLinkJsonV600, UpdateAbacRuleJsonV600, UpdateDynamicEntityRequestJsonV600}
|
||||
import code.api.v6_0_0.OBPAPI6_0_0
|
||||
import code.abacrule.{AbacRuleEngine, MappedAbacRuleProvider}
|
||||
import code.metrics.APIMetrics
|
||||
@ -795,6 +795,62 @@ trait APIMethods600 {
|
||||
}
|
||||
}
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
getDatabasePoolInfo,
|
||||
implementedInApiVersion,
|
||||
nameOf(getDatabasePoolInfo),
|
||||
"GET",
|
||||
"/system/database/pool",
|
||||
"Get Database Pool Information",
|
||||
"""Returns HikariCP connection pool information including:
|
||||
|
|
||||
|- Pool name
|
||||
|- Active connections: currently in use
|
||||
|- Idle connections: available in pool
|
||||
|- Total connections: active + idle
|
||||
|- Threads awaiting connection: requests waiting for a connection
|
||||
|- Configuration: max pool size, min idle, timeouts
|
||||
|
|
||||
|This helps diagnose connection pool issues such as connection leaks or pool exhaustion.
|
||||
|
|
||||
|Authentication is Required
|
||||
|""",
|
||||
EmptyBody,
|
||||
DatabasePoolInfoJsonV600(
|
||||
pool_name = "HikariPool-1",
|
||||
active_connections = 5,
|
||||
idle_connections = 3,
|
||||
total_connections = 8,
|
||||
threads_awaiting_connection = 0,
|
||||
maximum_pool_size = 10,
|
||||
minimum_idle = 2,
|
||||
connection_timeout_ms = 30000,
|
||||
idle_timeout_ms = 600000,
|
||||
max_lifetime_ms = 1800000,
|
||||
keepalive_time_ms = 0
|
||||
),
|
||||
List(
|
||||
AuthenticatedUserIsRequired,
|
||||
UserHasMissingRoles,
|
||||
UnknownError
|
||||
),
|
||||
List(apiTagSystem, apiTagApi),
|
||||
Some(List(canGetDatabasePoolInfo))
|
||||
)
|
||||
|
||||
lazy val getDatabasePoolInfo: OBPEndpoint = {
|
||||
case "system" :: "database" :: "pool" :: Nil JsonGet _ => {
|
||||
cc => implicit val ec = EndpointContext(Some(cc))
|
||||
for {
|
||||
(Full(u), callContext) <- authenticatedAccess(cc)
|
||||
_ <- NewStyle.function.hasEntitlement("", u.userId, canGetDatabasePoolInfo, callContext)
|
||||
} yield {
|
||||
val result = JSONFactory600.createDatabasePoolInfoJsonV600()
|
||||
(result, HttpCode.`200`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lazy val getCurrentConsumer: OBPEndpoint = {
|
||||
case "consumers" :: "current" :: Nil JsonGet _ => {
|
||||
cc => {
|
||||
@ -6924,7 +6980,16 @@ trait APIMethods600 {
|
||||
user_id = "user-456",
|
||||
bank_id = None,
|
||||
has_personal_entity = true,
|
||||
schema = net.liftweb.json.parse("""{"description": "User preferences", "required": ["theme"], "properties": {"theme": {"type": "string"}, "language": {"type": "string"}}}""").asInstanceOf[net.liftweb.json.JsonAST.JObject]
|
||||
schema = net.liftweb.json.parse("""{"description": "User preferences", "required": ["theme"], "properties": {"theme": {"type": "string"}, "language": {"type": "string"}}}""").asInstanceOf[net.liftweb.json.JsonAST.JObject],
|
||||
_links = Some(DynamicEntityLinksJsonV600(
|
||||
related = List(
|
||||
RelatedLinkJsonV600("list", "/obp/v6.0.0/my/customer_preferences", "GET"),
|
||||
RelatedLinkJsonV600("create", "/obp/v6.0.0/my/customer_preferences", "POST"),
|
||||
RelatedLinkJsonV600("read", "/obp/v6.0.0/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "GET"),
|
||||
RelatedLinkJsonV600("update", "/obp/v6.0.0/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "PUT"),
|
||||
RelatedLinkJsonV600("delete", "/obp/v6.0.0/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "DELETE")
|
||||
)
|
||||
))
|
||||
)
|
||||
)
|
||||
),
|
||||
@ -6979,7 +7044,16 @@ trait APIMethods600 {
|
||||
user_id = "user-456",
|
||||
bank_id = None,
|
||||
has_personal_entity = true,
|
||||
schema = net.liftweb.json.parse("""{"description": "User preferences", "required": ["theme"], "properties": {"theme": {"type": "string"}, "language": {"type": "string"}}}""").asInstanceOf[net.liftweb.json.JsonAST.JObject]
|
||||
schema = net.liftweb.json.parse("""{"description": "User preferences", "required": ["theme"], "properties": {"theme": {"type": "string"}, "language": {"type": "string"}}}""").asInstanceOf[net.liftweb.json.JsonAST.JObject],
|
||||
_links = Some(DynamicEntityLinksJsonV600(
|
||||
related = List(
|
||||
RelatedLinkJsonV600("list", "/obp/v6.0.0/my/customer_preferences", "GET"),
|
||||
RelatedLinkJsonV600("create", "/obp/v6.0.0/my/customer_preferences", "POST"),
|
||||
RelatedLinkJsonV600("read", "/obp/v6.0.0/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "GET"),
|
||||
RelatedLinkJsonV600("update", "/obp/v6.0.0/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "PUT"),
|
||||
RelatedLinkJsonV600("delete", "/obp/v6.0.0/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "DELETE")
|
||||
)
|
||||
))
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
@ -305,6 +305,20 @@ case class CacheInfoJsonV600(
|
||||
redis_available: Boolean
|
||||
)
|
||||
|
||||
case class DatabasePoolInfoJsonV600(
|
||||
pool_name: String,
|
||||
active_connections: Int,
|
||||
idle_connections: Int,
|
||||
total_connections: Int,
|
||||
threads_awaiting_connection: Int,
|
||||
maximum_pool_size: Int,
|
||||
minimum_idle: Int,
|
||||
connection_timeout_ms: Long,
|
||||
idle_timeout_ms: Long,
|
||||
max_lifetime_ms: Long,
|
||||
keepalive_time_ms: Long
|
||||
)
|
||||
|
||||
case class PostCustomerJsonV600(
|
||||
legal_name: String,
|
||||
customer_number: Option[String] = None,
|
||||
@ -486,6 +500,12 @@ case class AbacPoliciesJsonV600(
|
||||
policies: List[AbacPolicyJsonV600]
|
||||
)
|
||||
|
||||
// HATEOAS-style links for dynamic entity discoverability
|
||||
case class RelatedLinkJsonV600(rel: String, href: String, method: String)
|
||||
case class DynamicEntityLinksJsonV600(
|
||||
related: List[RelatedLinkJsonV600]
|
||||
)
|
||||
|
||||
// Dynamic Entity definition with fully predictable structure (v6.0.0 format)
|
||||
// No dynamic keys - entity name is an explicit field, schema describes the structure
|
||||
case class DynamicEntityDefinitionJsonV600(
|
||||
@ -494,7 +514,8 @@ case class DynamicEntityDefinitionJsonV600(
|
||||
user_id: String,
|
||||
bank_id: Option[String],
|
||||
has_personal_entity: Boolean,
|
||||
schema: net.liftweb.json.JsonAST.JObject
|
||||
schema: net.liftweb.json.JsonAST.JObject,
|
||||
_links: Option[DynamicEntityLinksJsonV600] = None
|
||||
)
|
||||
|
||||
case class MyDynamicEntitiesJsonV600(
|
||||
@ -1339,6 +1360,28 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
|
||||
)
|
||||
}
|
||||
|
||||
def createDatabasePoolInfoJsonV600(): DatabasePoolInfoJsonV600 = {
|
||||
import code.api.util.APIUtil
|
||||
|
||||
val ds = APIUtil.vendor.HikariDatasource.ds
|
||||
val config = APIUtil.vendor.HikariDatasource.config
|
||||
val pool = ds.getHikariPoolMXBean
|
||||
|
||||
DatabasePoolInfoJsonV600(
|
||||
pool_name = ds.getPoolName,
|
||||
active_connections = if (pool != null) pool.getActiveConnections else -1,
|
||||
idle_connections = if (pool != null) pool.getIdleConnections else -1,
|
||||
total_connections = if (pool != null) pool.getTotalConnections else -1,
|
||||
threads_awaiting_connection = if (pool != null) pool.getThreadsAwaitingConnection else -1,
|
||||
maximum_pool_size = config.getMaximumPoolSize,
|
||||
minimum_idle = config.getMinimumIdle,
|
||||
connection_timeout_ms = config.getConnectionTimeout,
|
||||
idle_timeout_ms = config.getIdleTimeout,
|
||||
max_lifetime_ms = config.getMaxLifetime,
|
||||
keepalive_time_ms = config.getKeepaliveTime
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create v6.0.0 response for GET /my/dynamic-entities
|
||||
*
|
||||
@ -1362,6 +1405,7 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
|
||||
def createMyDynamicEntitiesJson(dynamicEntities: List[code.dynamicEntity.DynamicEntityCommons]): MyDynamicEntitiesJsonV600 = {
|
||||
import net.liftweb.json.JsonAST._
|
||||
import net.liftweb.json.parse
|
||||
import net.liftweb.util.StringHelpers
|
||||
|
||||
MyDynamicEntitiesJsonV600(
|
||||
dynamic_entities = dynamicEntities.map { entity =>
|
||||
@ -1382,13 +1426,32 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
|
||||
throw new IllegalStateException(s"Could not extract schema for entity '${entity.entityName}' from metadataJson")
|
||||
)
|
||||
|
||||
// Build HATEOAS-style links for this dynamic entity
|
||||
val entityName = entity.entityName
|
||||
val idPlaceholder = StringHelpers.snakify(entityName + "Id").toUpperCase()
|
||||
val baseUrl = entity.bankId match {
|
||||
case Some(bankId) => s"/obp/v6.0.0/banks/$bankId/my/$entityName"
|
||||
case None => s"/obp/v6.0.0/my/$entityName"
|
||||
}
|
||||
|
||||
val links = DynamicEntityLinksJsonV600(
|
||||
related = List(
|
||||
RelatedLinkJsonV600("list", baseUrl, "GET"),
|
||||
RelatedLinkJsonV600("create", baseUrl, "POST"),
|
||||
RelatedLinkJsonV600("read", s"$baseUrl/$idPlaceholder", "GET"),
|
||||
RelatedLinkJsonV600("update", s"$baseUrl/$idPlaceholder", "PUT"),
|
||||
RelatedLinkJsonV600("delete", s"$baseUrl/$idPlaceholder", "DELETE")
|
||||
)
|
||||
)
|
||||
|
||||
DynamicEntityDefinitionJsonV600(
|
||||
dynamic_entity_id = entity.dynamicEntityId.getOrElse(""),
|
||||
entity_name = entity.entityName,
|
||||
user_id = entity.userId,
|
||||
bank_id = entity.bankId,
|
||||
has_personal_entity = entity.hasPersonalEntity,
|
||||
schema = schemaObj
|
||||
schema = schemaObj,
|
||||
_links = Some(links)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user