Make Resource Docs / Swagger available in all versions from 1.4.0. Tweak documentation / refactor a little

This commit is contained in:
Simon Redfern 2017-11-12 11:55:56 +01:00
parent 51983847cb
commit 02a67b459c
6 changed files with 181 additions and 91 deletions

View File

@ -38,7 +38,7 @@ import javax.mail.internet.MimeMessage
import code.accountholder.MapperAccountHolders
import code.actorsystem.ObpActorSystem
import code.api.Constant._
import code.api.ResourceDocs1_4_0.ResourceDocs
import code.api.ResourceDocs1_4_0._
import code.api._
import code.api.sandbox.SandboxApiCalls
import code.api.util.{APIUtil, ErrorMessages}
@ -226,10 +226,6 @@ class Boot extends MdcLoggable {
}
// Add the various API versions
// enableVersionIfAllowed(ApiVersion.v1_0)
// enableVersionIfAllowed(ApiVersion.v1_1)
// enableVersionIfAllowed(ApiVersion.v1_2)
// Can we depreciate the above?
enableVersionIfAllowed(ApiVersion.v1_2_1)
enableVersionIfAllowed(ApiVersion.v1_3_0)
enableVersionIfAllowed(ApiVersion.v1_4_0)
@ -242,15 +238,24 @@ class Boot extends MdcLoggable {
// TODO Wrap these with enableVersionIfAllowed as well
//add management apis
LiftRules.statelessDispatch.append(ImporterAPI)
//LiftRules.statelessDispatch.append(AccountsAPI)
// add other apis
LiftRules.statelessDispatch.append(BankMockAPI)
LiftRules.statelessDispatch.append(BankMockAPI) // Do we still need this?
//////////////////////////////////////////////////////////////////////////////////////////////////
// Resource Docs are used in the process of surfacing endpoints so we enable them explicitly
// to avoid a circular dependency.
// Make the (currently identical) endpoints available to different versions.
LiftRules.statelessDispatch.append(ResourceDocs140)
LiftRules.statelessDispatch.append(ResourceDocs200)
LiftRules.statelessDispatch.append(ResourceDocs210)
LiftRules.statelessDispatch.append(ResourceDocs220)
LiftRules.statelessDispatch.append(ResourceDocs300)
////////////////////////////////////////////////////
// Add Resource Docs These are treated separately else we have circular dependency.
LiftRules.statelessDispatch.append(ResourceDocs)
// LiftRules.statelessDispatch.append(Metrics) TODO: see metric menu entry below

View File

@ -1,24 +0,0 @@
package code.api.ResourceDocs1_4_0
import code.api.OBPRestHelper
import code.util.Helper.MdcLoggable
object ResourceDocs extends OBPRestHelper with ResourceDocsAPIMethods with MdcLoggable {
val version = "1.4.0" // Does it make sense to have this version match an api version?
val versionStatus = "UNKNOWN"
val routes = List(
ImplementationsResourceDocs.getResourceDocsObp,
ImplementationsResourceDocs.getResourceDocsSwagger
)
routes.foreach(route => {
oauthServe(apiPrefix{route})
})
}

View File

@ -0,0 +1,73 @@
package code.api.ResourceDocs1_4_0
import code.api.OBPRestHelper
import code.util.Helper.MdcLoggable
object ResourceDocs140 extends OBPRestHelper with ResourceDocsAPIMethods with MdcLoggable {
val version = "1.4.0" // We match other api versions so API explorer can easily use the path.
val versionStatus = "STABLE"
val routes = List(
ImplementationsResourceDocs.getResourceDocsObp,
ImplementationsResourceDocs.getResourceDocsSwagger
)
routes.foreach(route => {
oauthServe(apiPrefix{route})
})
}
// Hack to provide Resource Docs / Swagger on endpoints other than 1.4.0 where it is defined.
object ResourceDocs200 extends OBPRestHelper with ResourceDocsAPIMethods with MdcLoggable {
val version = "2.0.0" // We match other api versions so API explorer can easily use the path.
val versionStatus = "DRAFT"
val routes = List(
ImplementationsResourceDocs.getResourceDocsObp,
ImplementationsResourceDocs.getResourceDocsSwagger
)
routes.foreach(route => {
oauthServe(apiPrefix{route})
})
}
// Hack to provide Resource Docs / Swagger on endpoints other than 1.4.0 where it is defined.
object ResourceDocs210 extends OBPRestHelper with ResourceDocsAPIMethods with MdcLoggable {
val version = "2.1.0" // We match other api versions so API explorer can easily use the path.
val versionStatus = "DRAFT"
val routes = List(
ImplementationsResourceDocs.getResourceDocsObp,
ImplementationsResourceDocs.getResourceDocsSwagger
)
routes.foreach(route => {
oauthServe(apiPrefix{route})
})
}
// Hack to provide Resource Docs / Swagger on endpoints other than 1.4.0 where it is defined.
object ResourceDocs220 extends OBPRestHelper with ResourceDocsAPIMethods with MdcLoggable {
val version = "2.2.0" // We match other api versions so API explorer can easily use the path.
val versionStatus = "DRAFT"
val routes = List(
ImplementationsResourceDocs.getResourceDocsObp,
ImplementationsResourceDocs.getResourceDocsSwagger
)
routes.foreach(route => {
oauthServe(apiPrefix{route})
})
}
// Hack to provide Resource Docs / Swagger on endpoints other than 1.4.0 where it is defined.
object ResourceDocs300 extends OBPRestHelper with ResourceDocsAPIMethods with MdcLoggable {
val version = "3.0.0" // We match other api versions so API explorer can easily use the path.
val versionStatus = "DRAFT"
val routes = List(
ImplementationsResourceDocs.getResourceDocsObp,
ImplementationsResourceDocs.getResourceDocsSwagger
)
routes.foreach(route => {
oauthServe(apiPrefix{route})
})
}

View File

@ -50,7 +50,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
val ImplementationsResourceDocs = new Object() {
val resourceDocs = ArrayBuffer[ResourceDoc]()
val localResourceDocs = ArrayBuffer[ResourceDoc]()
val emptyObjectJson = EmptyClassJson()
val statedApiVersion : String = "1_4_0"
@ -100,40 +100,21 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
logger.debug(s"There are ${activeResourceDocs.length} resource docs available to $requestedApiVersion")
val activePlusLocalResourceDocs = ArrayBuffer[ResourceDoc]()
activePlusLocalResourceDocs ++= activeResourceDocs
activePlusLocalResourceDocs ++= localResourceDocs
logger.debug(s"There are ${activePlusLocalResourceDocs.length} resource docs (including local) available to $requestedApiVersion")
// Sort by endpoint, verb. Thus / is shown first then /accounts and /banks etc. Seems to read quite well like that.
Some(activeResourceDocs.toList.sortBy(rd => (rd.requestUrl, rd.requestVerb)))
Some(activePlusLocalResourceDocs.toList.sortBy(rd => (rd.requestUrl, rd.requestVerb)))
}
resourceDocs += ResourceDoc(
getResourceDocsObp,
statedApiVersion,
"getResourceDocsObp",
"GET",
"/resource-docs/API_VERSION/obp",
"Get Resource Documentation in OBP format.",
"""Returns documentation about the RESTful resources on this server including example body for POST or PUT requests.
| So the OBP API Explorer (and other apps) can display and work with the API documentation.
| This information is used to create Swagger files.
|<ul>
|<li> operation_id is concatenation of version and function and should be unque (the aim of this is to allow links to code) </li>
|<li> version references the version that the API call is defined in.</li>
|<li> function is the (scala) function.</li>
|<li> request_url is empty for the root call, else the path.</li>
|<li> summary is a short description inline with the swagger terminology. </li>
|<li> description may contain html markup (generated from markdown on the server).</li>
|</ul>
""",
emptyObjectJson,
emptyObjectJson,
UnknownError :: Nil,
Catalogs(notCore, notPSD2, notOBWG),
List(apiTagApi)
)
// Provides resource documents so that API Explorer (or other apps) can display API documentation
// Note: description uses html markup because original markdown doesn't easily support "_" and there are multiple versions of markdown.
// TODO constrain version?
@ -216,7 +197,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
}
logger.info(s"tagsOption is $tags")
// So we can produce a reduced list of resource docs to prevent manual editing of swagger files.
val rawPartialFunctionNames = S.param("functions")
val partialFunctionNames: Option[List[String]] =
@ -243,7 +224,40 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
(showCore, showPSD2, showOBWG, tags, partialFunctionNames)
}
def getResourceDocsObp : PartialFunction[Req, Box[User] => Box[JsonResponse]] = {
localResourceDocs += ResourceDoc(
getResourceDocsObp,
statedApiVersion,
"getResourceDocsObp",
"GET",
"/resource-docs/API_VERSION/obp",
"Get Resource Documentation in OBP format.",
"""Returns documentation about the RESTful resources on this server including example bodies for POST and PUT requests.
| This endpoint is used by OBP API Explorer to display and work with the API documentation.
| Most (but not all) fields are also available in swagger format.
| You may query this endpoint with tags parameter e.g. ?tags=Account,Bank
| You may query this endpoint with functions parameter e.g. ?functions=enableDisableConsumers,getConnectorMetrics
|<ul>
|<li> operation_id is concatenation of version and function and should be unque (the aim of this is to allow links to code) </li>
|<li> version references the version that the API call is defined in.</li>
|<li> function is the (scala) function.</li>
|<li> request_url is empty for the root call, else the path.</li>
|<li> summary is a short description inline with the swagger terminology. </li>
|<li> description may contain html markup (generated from markdown on the server).</li>
|</ul>
""",
emptyObjectJson,
emptyObjectJson,
UnknownError :: Nil,
Catalogs(notCore, notPSD2, notOBWG),
List(apiTagApi)
)
// Provides resource documents so that API Explorer (or other apps) can display API documentation
// Note: description uses html markup because original markdown doesn't easily support "_" and there are multiple versions of markdown.
def getResourceDocsObp : PartialFunction[Req, Box[User] => Box[JsonResponse]] = {
case "resource-docs" :: requestedApiVersionString :: "obp" :: Nil JsonGet _ => {
val (showCore, showPSD2, showOBWG, tags, partialFunctions) = getParams()
user => {
@ -260,6 +274,42 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
}
}
localResourceDocs += ResourceDoc(
getResourceDocsSwagger,
statedApiVersion,
"getResourceDocsSwagger",
"GET",
"/resource-docs/v.2.2.0/swagger",
"Get Resource Documentation in Swagger format. Work In Progress!",
"""Returns documentation about the RESTful resources on this server in Swagger format.
|
| You may query this endpoint with tags parameter e.g. ?tags=Account,Bank
| You may query this endpoint with functions parameter e.g. ?functions=enableDisableConsumers,getConnectorMetrics
|
| Also see the Resource Doc endpoint.
|
""",
emptyObjectJson,
emptyObjectJson,
UnknownError :: Nil,
Catalogs(notCore, notPSD2, notOBWG),
List(apiTagApi)
)
def getResourceDocsSwagger : PartialFunction[Req, Box[User] => Box[JsonResponse]] = {
case "resource-docs" :: requestedApiVersion :: "swagger" :: Nil JsonGet _ => {
val (showCore, showPSD2, showOBWG, resourceDocTags, partialFunctions) = getParams()
user => getResourceDocsSwaggerCached(showCore, showPSD2, showOBWG, requestedApiVersion, resourceDocTags, partialFunctions)
}
}
/*
Filter Resource Docs based on the query parameters, else return the full list.
We don't assume a default catalog (as API Explorer does)
@ -321,7 +371,7 @@ def filterResourceDocs(allResources: List[ResourceDoc], showCore: Option[Boolean
// tags param was not mentioned in url or was empty, so return all
case None => filteredResources4
}
val resourcesToUse = filteredResources5.toSet.toList
@ -347,22 +397,7 @@ def filterResourceDocs(allResources: List[ResourceDoc], showCore: Option[Boolean
resourcesToUse
}
resourceDocs += ResourceDoc(
getResourceDocsSwagger,
statedApiVersion,
"getResourceDocsSwagger",
"GET",
"/resource-docs/v.2.2.0/swagger",
"Get Resource Documentation in Swagger format. Work In Progress!",
"""Returns documentation about the RESTful resources on this server in Swagger format.
| Work in Progress.
""",
emptyObjectJson,
emptyObjectJson,
UnknownError :: Nil,
Catalogs(notCore, notPSD2, notOBWG),
List(apiTagApi)
)
private def getResourceDocsSwaggerCached(showCore: Option[Boolean], showPSD2: Option[Boolean], showOBWG: Option[Boolean], requestedApiVersionString : String, resourceDocTags: Option[List[ResourceDocTag]], partialFunctionNames: Option[List[String]]) : Box[JsonResponse] = {
@ -388,24 +423,20 @@ def filterResourceDocs(allResources: List[ResourceDoc], showCore: Option[Boolean
}
def getResourceDocsSwagger : PartialFunction[Req, Box[User] => Box[JsonResponse]] = {
case "resource-docs" :: requestedApiVersion :: "swagger" :: Nil JsonGet _ => {
val (showCore, showPSD2, showOBWG, resourceDocTags, partialFunctions) = getParams()
user => getResourceDocsSwaggerCached(showCore, showPSD2, showOBWG, requestedApiVersion, resourceDocTags, partialFunctions)
}
}
if (Props.devMode) {
resourceDocs += ResourceDoc(
localResourceDocs += ResourceDoc(
dummy(statedApiVersion, "DUMMY"),
statedApiVersion,
"testResourceDoc",
"GET",
"/dummy",
"I am only a test resource Doc",
"Test Resource Doc.",
"""
|I am only a test Resource Doc
|
|#This should be H1
|

View File

@ -997,7 +997,7 @@ object APIUtil extends MdcLoggable {
// Used to document the API calls
case class ResourceDoc(
partialFunction : OBPEndpoint, // PartialFunction[Req, Box[User] => Box[JsonResponse]],
implementedInApiVersion: String, // TODO: Constrain to certain strings?
implementedInApiVersion: String, // TODO: Use ApiVersion enumeration instead of string
partialFunctionName: String, // The string name of the partial function that implements this resource. Could use it to link to the source code that implements the call
requestVerb: String, // GET, POST etc. TODO: Constrain to GET, POST etc.
requestUrl: String, // The URL (not including /obp/vX.X). Starts with / No trailing slash. TODO Constrain the string?
@ -1549,6 +1549,9 @@ Versions are groups of endpoints in a file
def dottedApiVersion (apiVersion: ApiVersion) : String = apiVersion.toString.replace("_", ".").replace("v","")
def vDottedApiVersion (apiVersion: ApiVersion) : String = apiVersion.toString.replace("_", ".")
// TODO make this a method of the ApiVersion object so its easier to call
def noV (apiVersion: ApiVersion) : String = apiVersion.toString.replace("v", "").replace("V","")
def getAllowedEndpoints (endpoints : List[OBPEndpoint], resourceDocs: ArrayBuffer[ResourceDoc]) : List[OBPEndpoint] = {

View File

@ -50,6 +50,8 @@ import code.api.util.APIUtil.authenticationRequiredMessage
import code.api.util.ErrorMessages._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
import code.api.util.APIUtil.noV
trait APIMethods140 extends MdcLoggable with APIMethods130 with APIMethods121{
//needs to be a RestHelper to get access to JsonGet, JsonPost, etc.
// We add previous APIMethods so we have access to the Resource Docs
@ -59,7 +61,7 @@ trait APIMethods140 extends MdcLoggable with APIMethods130 with APIMethods121{
val resourceDocs = ArrayBuffer[ResourceDoc]()
val emptyObjectJson = EmptyClassJson()
val apiVersion : String = "1_4_0"
val apiVersion : String = noV(ApiVersion.v1_4_0) // "1_4_0"
val apiVersionStatus : String = "STABLE"
val exampleDateString : String ="22/08/2013"