Merge pull request #109 from hongwei1/develop

feature/separated the dynamic and static endpoints
This commit is contained in:
Simon Redfern 2020-11-10 12:32:02 +01:00 committed by GitHub
commit 070f9a5a43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 21 deletions

View File

@ -10,11 +10,12 @@ import code.util.Helper
import code.util.Helper.MdcLoggable
import code.util.cache.Caching
import net.liftweb.common.{Box, Failure, Full, _}
import net.liftweb.http.{RequestVar, S}
import net.liftweb.http.{RequestVar, S, SessionVar}
import net.liftweb.json.JsonAST.{JBool, JValue}
import net.liftweb.json.JsonDSL._
import net.liftweb.json._
import net.liftweb.util.Helpers.{intToTimeSpanBuilder=>_,_} //This will break the cache days, so here we hide it in import
import net.liftweb.util.Helpers.{intToTimeSpanBuilder => _, _}
import scala.xml.NodeSeq
import com.tesobe.CacheKeyFromArguments
import scala.collection.immutable.{List, Nil}
@ -50,7 +51,8 @@ object ObpAPI extends Loggable {
def allBanks : Box[BanksJson]= {
allBanksVar.get match {
case Full(a) => Full(a)
case _ => ObpGet(s"$obpPrefix/v3.1.0/banks").flatMap(_.extractOpt[BanksJson])
case _ => allBanksVar.set(ObpGet(s"$obpPrefix/v3.1.0/banks").flatMap(_.extractOpt[BanksJson]))
allBanksVar.get
}
}
@ -145,17 +147,50 @@ object ObpAPI extends Loggable {
/**
* The request vars ensure that for one page load, the same API call isn't made multiple times
*/
object allResoucesVar extends SessionVar[Box[ResourceDocsJson]] (Empty)
// Returns Json containing Resource Docs
def getResourceDocsJson(apiVersion : String) : Box[ResourceDocsJson] = {
val requestParams = List("tags", "language", "functions")
def getResourceDocsJson(apiVersion : String) : List[ResourceDocJson] = {
//Note: ?content=true&content=false
// if there are two content parameters there, only the first one is valid for the api call.
// so requestParams have the high priority
val requestParams = List("tags", "language", "functions", "content")
.map(paramName => (paramName, S.param(paramName)))
.collect{
case (paramName, Full(paramValue)) if(paramValue.trim.size > 0) => s"$paramName=$paramValue"
}
.mkString("?", "&", "")
ObpGet(s"$obpPrefix/v3.1.0/resource-docs/$apiVersion/obp$requestParams").map(extractResourceDocsJson)
val staticResourcesDocs= getStaticResourceDocs(apiVersion,requestParams)
if(requestParams.contains("content=static")) {
staticResourcesDocs
} else if (requestParams.contains("content=dynamic")){
getDynamicResourceDocs(apiVersion,requestParams)
} else{
val dynamicResourcesDocs= getDynamicResourceDocs(apiVersion,requestParams)
staticResourcesDocs ++ dynamicResourcesDocs
}
}
// static resourceDocs can be cached for a long time, only be changed when new deployment.
val getStaticResourceDocsJsonTTL: FiniteDuration = 365 days
def getStaticResourceDocs(apiVersion : String, requestParams: String): List[ResourceDocJson] = {
var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString)
CacheKeyFromArguments.buildCacheKey {
Caching.memoizeSyncWithProvider(Some(cacheKey.toString()))(getStaticResourceDocsJsonTTL) {
ObpGet(s"$obpPrefix/v3.1.0/resource-docs/$apiVersion/obp$requestParams&content=static").map(extractResourceDocsJson).map(_.resource_docs).head
}
}
}
def getDynamicResourceDocs(apiVersion : String, requestParams: String) =
ObpGet(s"$obpPrefix/v3.1.0/resource-docs/$apiVersion/obp$requestParams&content=dynamic").map(extractResourceDocsJson).map(_.resource_docs).head
/**
* extract ResourceDocsJson and output details of error if extract json to case class fail
@ -211,6 +246,7 @@ object OBPRequest extends MdcLoggable {
implicit val formats = DefaultFormats
//returns a tuple of the status code, response body and list of headers
def apply(apiPath : String, jsonBody : Option[JValue], method : String, headers : List[Header]) : Box[(Int, String, List[String])] = {
logger.debug(s"before $apiPath call:")
val statusAndBody = tryo {
val credentials = OAuthClient.getAuthorizedCredential
val apiUrl = OAuthClient.currentApiBaseUrl
@ -271,7 +307,7 @@ object OBPRequest extends MdcLoggable {
(status, builder.toString(), adjustedResponseHeaders)
}
statusAndBody pass {
val result = statusAndBody pass {
case Failure(msg, ex, _) => {
val sw = new StringWriter()
val writer = new PrintWriter(sw)
@ -280,6 +316,8 @@ object OBPRequest extends MdcLoggable {
}
case _ => Unit
}
logger.debug(s"after $apiPath call:")
result
}
}
@ -375,7 +413,11 @@ object APIUtils extends MdcLoggable {
def getAPIResponseBody(responseCode : Int, body : String) : Box[JValue] = {
responseCode match {
case 200 | 201 | 202 |204 => tryo{parse(body)}
case 200 | 201 | 202 |204 =>
logger.debug("Before getAPIResponseBody(String ->JValue): ")
val jvalue = tryo{parse(body)}
logger.debug("After getAPIResponseBody(String -> JValue): ")
jvalue
case _ => {
val failMsg = "Bad response code (" + responseCode + ") from OBP API server: " + body
logger.warn(failMsg)

View File

@ -218,6 +218,14 @@ WIP to add comments on resource docs. This code copied from Sofit.
val languagesParamString = "&language=" + rawLanguageParam.mkString(",")
logger.info(s"languagesParamString is $languagesParamString")
val rawContentParam = S.param("content")
logger.info(s"contentParam is $rawContentParam")
val contentParamString = "&content=" + rawContentParam.mkString(",")
logger.info(s"contentParamString is $contentParamString")
val tagsParam: Option[List[String]] = rawTagsParam match {
// if tags= is supplied in the url we want to ignore it
@ -246,6 +254,11 @@ WIP to add comments on resource docs. This code copied from Sofit.
case _ => ""
}
val contentHeadline : String = rawContentParam match {
case Full(x) => x
case _ => ""
}
val implementedHereHeadline : String = nativeParam match {
case Some(true) => "(those added or modified in this version)"
case Some(false) => "(those inherited from previous versions)"
@ -395,23 +408,23 @@ WIP to add comments on resource docs. This code copied from Sofit.
val baseVersionUrl = s"${OAuthClient.currentApiBaseUrl}"
// Link to the API endpoint for the resource docs json TODO change apiVersion so it doesn't have a "v" prefix
val resourceDocsPath = s"${OAuthClient.currentApiBaseUrl}/obp/v1.4.0/resource-docs/${apiVersion.stripPrefix("v")}/obp?${tagsParamString}${languagesParamString}"
val resourceDocsPath = s"${OAuthClient.currentApiBaseUrl}/obp/v1.4.0/resource-docs/${apiVersion.stripPrefix("v")}/obp?${tagsParamString}${languagesParamString}${contentParamString}"
// Link to the API endpoint for the swagger json
val swaggerPath = s"${OAuthClient.currentApiBaseUrl}/obp/v1.4.0/resource-docs/${apiVersion.stripPrefix("v")}/swagger?${tagsParamString}${languagesParamString}"
val swaggerPath = s"${OAuthClient.currentApiBaseUrl}/obp/v1.4.0/resource-docs/${apiVersion.stripPrefix("v")}/swagger?${tagsParamString}${languagesParamString}${contentParamString}"
val chineseVersionPath = "?language=zh"
val allPartialFunctions = "/partial-functions.html"
//Note > this method is only for partial-functions.html .
def showPartialFunctions = {
// Get a list of resource docs from the API server
// This will throw an exception if resource_docs key is not populated
// Convert the json representation to ResourceDoc (pretty much a one to one mapping)
// The overview contains html. Just need to convert it to a NodeSeq so the template will render it as such
val allResources: List[ResourceDocJson] = for {
rs <- getResourceDocsJson(apiVersion).toList
r <- rs.resource_docs
} yield r
rs <- getResourceDocsJson(apiVersion)
} yield rs
// The list generated here might be used by an administrator as a white or black list of API calls for the API itself.
val commaSeparatedListOfResources = allResources.map(_.implemented_by.function).mkString("[", ", ", "]")
@ -596,14 +609,13 @@ WIP to add comments on resource docs. This code copied from Sofit.
def showResources = {
logger.debug("before showResources:")
// Get a list of resource docs from the API server
// This will throw an exception if resource_docs key is not populated
// Convert the json representation to ResourceDoc (pretty much a one to one mapping)
// The overview contains html. Just need to convert it to a NodeSeq so the template will render it as such
val allResources = for {
rs <- getResourceDocsJson(apiVersion).toList
r <- rs.resource_docs
r <- getResourceDocsJson(apiVersion)
} yield ResourceDocPlus(
//in OBP-API, before it returned v3_1_0, but now, only return v3.1.0
//But this filed will be used in JavaScript, so need clean the field.
@ -735,7 +747,7 @@ WIP to add comments on resource docs. This code copied from Sofit.
// Title / Headline we display including count of APIs
val headline : String = s"""
${apiVersionRequested.stripPrefix("OBP").stripPrefix("BG").stripPrefix("STET").stripPrefix("UK")}
$tagsHeadline $languageHeadline $implementedHereHeadline (${resources.length} APIs)
$tagsHeadline $languageHeadline $contentHeadline $implementedHereHeadline (${resources.length} APIs)
""".trim()
@ -912,7 +924,7 @@ WIP to add comments on resource docs. This code copied from Sofit.
val thisApplicationUrl = s"${CurrentReq.value.uri}?version=${apiVersionRequested}&list-all-banks=${listAllBanks}${tagsParamString}${languagesParamString}"
val thisApplicationUrl = s"${CurrentReq.value.uri}?version=${apiVersionRequested}&list-all-banks=${listAllBanks}${tagsParamString}${languagesParamString}${contentParamString}"
val obpVersionUrls: List[(String, String)] = obpVersionsSupported.map(i => (i.replace("OBPv", "v"), s"?version=${i}&list-all-banks=${listAllBanks}"))
@ -1169,8 +1181,7 @@ WIP to add comments on resource docs. This code copied from Sofit.
// In case we use Extraction.decompose
implicit val formats = net.liftweb.json.DefaultFormats
"#login_status_message" #> loggedInStatusMessage &
val cssResult = "#login_status_message" #> loggedInStatusMessage &
"#bank_selector" #> doBankSelect _ &
"#account_selector" #> doAccountSelect _ &
"#view_selector" #> doViewSelect _ &
@ -1245,7 +1256,7 @@ WIP to add comments on resource docs. This code copied from Sofit.
else if (resources.find(_.id == currentOperationId).map(_.tags.head).getOrElse("API")==resources.find(_.id == i.id).map(_.tags.head).getOrElse("API")) //If the Tag is the current Tag.We do not need parameters.
s"#${i.id}"
else
s"?version=$apiVersionRequested&operation_id=${i.id}&bank_id=${presetBankId}&account_id=${presetAccountId}&view_id=${presetViewId}&counterparty_id=${presetCounterpartyId}&transaction_id=${presetTransactionId}#${i.id}") &
s"?version=$apiVersionRequested&operation_id=${i.id}&currentTag=${i.tags.head}&bank_id=${presetBankId}&account_id=${presetAccountId}&view_id=${presetViewId}&counterparty_id=${presetCounterpartyId}&transaction_id=${presetTransactionId}#${i.id}") &
"@api_list_item_link *" #> i.summary &
"@api_list_item_link [id]" #> s"index_of_${i.id}"
// ".content-box__available-since *" #> s"Implmented in ${i.implementedBy.version} by ${i.implementedBy.function}"
@ -1411,6 +1422,8 @@ WIP to add comments on resource docs. This code copied from Sofit.
}
}
}
logger.debug("after showResources:")
cssResult
}
def showGlossary = {