1 #TODO: Some methods do the same thing like collecion.index and collection.list.
2 # Make one implementation of the method and make other reference to it.
4 getAPIDocument <- function(){
5 url <- "https://4xphq.arvadosapi.com/discovery/v1/apis/arvados/v1/rest"
6 serverResponse <- httr::RETRY("GET", url = url)
8 httr::content(serverResponse, as = "parsed", type = "application/json")
12 generateAPI <- function()
14 JSONDocument <- getAPIDocument()
16 generateArvadosClasses(JSONDocument)
17 generateArvadosAPIClass(JSONDocument)
20 generateArvadosAPIClass <- function(discoveryDocument)
22 classMetaData <- discoveryDocument$schemas
23 functionResources <- discoveryDocument$resources
24 resourceNames <- names(functionResources)
26 arvadosAPIHeader <- generateAPIClassHeader()
27 arvadosAPIFooter <- generateAPIClassFooter()
29 arvadosMethods <- Map(function(resource, resourceName)
31 methodNames <- names(resource$methods)
33 functions <- Map(function(methodMetaData, methodName)
35 methodName <- paste0(resourceName, ".", methodName)
36 createFunction(methodName, methodMetaData, classMetaData)
38 }, resource$methods, methodNames)
40 unlist(unname(functions))
42 }, functionResources, resourceNames)
44 arvadosClass <- c(arvadosAPIHeader, arvadosMethods, arvadosAPIFooter)
46 #TODO: Save to a file or load in memory?
47 fileConn <- file("./R/Arvados.R", "w")
48 writeLines(unlist(arvadosClass), fileConn)
53 getFunctionName <- function(functionMetaData)
55 stringr::str_replace(functionMetaData$id, "arvados.", "")
58 #TODO: Make sure that arguments that are required always go first.
59 # This is not the case if request$required is false.
60 getFunctionArguments <- function(functionMetaData)
62 request <- functionMetaData$request
63 requestArgument <- NULL
67 requestArgument <- names(request$properties)
69 requestArgument <- paste(names(request$properties), "=", "NULL")
71 argNames <- names(functionMetaData$parameters)
73 args <- sapply(argNames, function(argName)
75 arg <- functionMetaData$parameters[[argName]]
79 if(!is.null(arg$default))
80 return(paste0(argName, " = ", "\"", arg$default, "\""))
82 return(paste(argName, "=", "NULL"))
88 paste0(c(requestArgument, args))
91 getFunctionBody <- function(functionMetaData, classMetaData)
93 url <- getRequestURL(functionMetaData)
94 headers <- getRequestHeaders()
95 requestQueryList <- getRequestQueryList(functionMetaData)
96 requestBody <- getRequestBody(functionMetaData)
97 request <- getRequest(functionMetaData)
98 response <- getResponse(functionMetaData)
99 errorCheck <- getErrorCheckingCode()
100 returnObject <- getReturnObject(functionMetaData, classMetaData)
106 request, response, "",
110 paste0("\t\t\t", body)
113 getErrorCheckingCode <- function()
115 c("if(!is.null(resource$errors))", "\tstop(resource$errors)")
118 getRequestBody <- function(functionMetaData)
120 request <- functionMetaData$request
122 if(is.null(request) || !request$required)
123 return("body <- NULL")
125 requestParameterName <- names(request$properties)[1]
126 paste0("body <- ", requestParameterName, "$toJSON()")
129 getRequestHeaders <- function()
131 c("headers <- list(Authorization = paste(\"OAuth2\", private$token), ",
132 " \"Content-Type\" = \"application/json\")")
135 getReturnObject <- function(functionMetaData, classMetaData)
137 returnClass <- functionMetaData$response[["$ref"]]
138 classArguments <- getReturnClassArguments(returnClass, classMetaData)
141 if(returnClass == "Collection")
142 return(c(formatArgs("collection <- Collection$new(", "\t",
143 classArguments, ")", 40),
145 "collection$setRESTService(private$REST)",
148 formatArgs(paste0(returnClass, "$new("), "\t", classArguments, ")", 40)
151 getReturnClassArguments <- function(className, classMetaData)
153 classArguments <- unique(names(classMetaData[[className]]$properties))
155 arguments <- sapply(classArguments, function(arg)
157 paste0(arg, " = resource$", arg)
163 getRequest <- function(functionMetaData)
165 method <- functionMetaData$httpMethod
166 c(paste0("response <- private$REST$http$exec(\"", method, "\", url, headers, body,"),
167 " queryArgs, private$numRetries)")
170 getResponse <- function(functionMetaData)
172 "resource <- private$REST$httpParser$parseJSONResponse(response)"
175 getRequestURL <- function(functionMetaData)
177 endPoint <- functionMetaData$path
178 endPoint <- stringr::str_replace_all(endPoint, "\\{", "${")
179 url <- c(paste0("endPoint <- stringr::str_interp(\"", endPoint, "\")"),
180 paste0("url <- paste0(private$host, endPoint)"))
184 getRequestQueryList <- function(functionMetaData)
186 args <- names(functionMetaData$parameters)
188 if(length(args) == 0)
189 return("queryArgs <- NULL")
191 args <- sapply(args, function(arg) paste0(arg, " = ", arg))
192 collapsedArgs <- paste0(args, collapse = ", ")
194 if(nchar(collapsedArgs) > 40)
195 return(formatArgs("queryArgs <- list(", "\t", args, ")", 40))
197 return(paste0("queryArgs <- list(", collapsedArgs, ")"))
200 createFunction <- function(functionName, functionMetaData, classMetaData)
202 args <- getFunctionArguments(functionMetaData)
203 body <- getFunctionBody(functionMetaData, classMetaData)
204 funSignature <- getFunSignature(functionName, args)
206 functionString <- c(funSignature,
214 getFunSignature <- function(funName, args)
216 collapsedArgs <- paste0(args, collapse = ", ")
218 if(nchar(collapsedArgs) > 40)
220 return(paste0("\t\t",
221 formatArgs(paste(funName, "= function("),
222 "\t", args, ")", 40)))
226 return(paste0("\t\t", funName, " = function(", collapsedArgs, ")"))
230 generateAPIClassHeader <- function()
233 "Arvados <- R6::R6Class(",
239 "\t\tinitialize = function(authToken = NULL, hostName = NULL, numRetries = 0)",
241 "\t\t\tif(!is.null(hostName))",
242 "\t\t\t\tSys.setenv(ARVADOS_API_HOST = hostName)",
244 "\t\t\tif(!is.null(authToken))",
245 "\t\t\t\tSys.setenv(ARVADOS_API_TOKEN = authToken)",
247 "\t\t\thostName <- Sys.getenv(\"ARVADOS_API_HOST\")",
248 "\t\t\ttoken <- Sys.getenv(\"ARVADOS_API_TOKEN\")",
250 "\t\t\tif(hostName == \"\" | token == \"\")",
251 "\t\t\t\tstop(paste(\"Please provide host name and authentification token\",",
252 "\t\t\t\t\t\t \"or set ARVADOS_API_HOST and ARVADOS_API_TOKEN\",",
253 "\t\t\t\t\t\t \"environment variables.\"))",
255 "\t\t\tprivate$token <- token",
256 "\t\t\tprivate$host <- paste0(\"https://\", hostName, \"/arvados/v1/\")",
257 "\t\t\tprivate$numRetries <- numRetries",
258 "\t\t\tprivate$REST <- RESTService$new(token, hostName,",
259 "\t\t\t HttpRequest$new(), HttpParser$new(),",
260 "\t\t\t numRetries)",
265 generateAPIClassFooter <- function()
267 c("\t\tgetHostName = function() private$host,",
268 "\t\tgetToken = function() private$token,",
269 "\t\tsetRESTService = function(newREST) private$REST <- newREST",
277 "\t\tnumRetries = NULL",
280 "\tcloneable = FALSE",
284 generateArvadosClasses <- function(resources)
286 classes <- sapply(resources$schemas, function(classSchema)
288 #NOTE: Collection is implemented manually.
289 if(classSchema$id != "Collection")
290 getArvadosClass(classSchema)
294 unlist(unname(classes))
296 fileConn <- file("./R/ArvadosClasses.R", "w")
297 writeLines(unlist(classes), fileConn)
302 getArvadosClass <- function(classSchema)
304 name <- classSchema$id
305 fields <- unique(names(classSchema$properties))
306 constructorArgs <- paste(fields, "= NULL")
307 documentation <- getClassDocumentation(classSchema, constructorArgs)
309 classString <- c(documentation,
310 paste0(name, " <- R6::R6Class("),
312 paste0("\t\"", name, "\","),
315 paste0("\t\t", fields, " = NULL,"),
317 paste0("\t\t", formatArgs("initialize = function(", "\t\t",
318 constructorArgs, ")", 40)),
320 paste0("\t\t\tself$", fields, " <- ", fields),
322 paste0("\t\t\t", formatArgs("private$classFields <- c(", "\t",
326 "\t\ttoJSON = function() {",
327 "\t\t\tfields <- sapply(private$classFields, function(field)",
329 "\t\t\t\tself[[field]]",
330 "\t\t\t}, USE.NAMES = TRUE)",
332 paste0("\t\t\tjsonlite::toJSON(list(\"", tolower(name), "\" =
333 Filter(Negate(is.null), fields)), auto_unbox = TRUE)"),
338 "\t\tclassFields = NULL",
341 "\tcloneable = FALSE",
346 getClassDocumentation <- function(classSchema, constructorArgs)
348 name <- classSchema$id
349 description <- classSchema$description
350 nameLowercaseFirstLetter <- paste0(tolower(substr(name, 1, 1)),
351 substr(name, 2, nchar(name)))
352 c(paste0("#' ", name),
354 paste0("#' ", description),
356 "#' @section Usage:",
357 formatArgs(paste0("#' \\preformatted{",
358 nameLowercaseFirstLetter, " -> ", name, "$new("),
359 "#' \t", constructorArgs, ")", 50),
363 paste0("#' @section Arguments:"),
365 paste0("#' ", getClassArgumentDescription(classSchema)),
368 paste0("#' @name ", name),
374 getClassArgumentDescription <- function(classSchema)
376 argDoc <- sapply(classSchema$properties, function(arg)
378 paste0("{", arg$description, "}")
381 paste0("\\item{", names(classSchema$properties), "}", argDoc)
384 formatArgs <- function(prependAtStart, prependToEachSplit,
385 args, appendAtEnd, lineLength)
389 args[1:(length(args) - 1)] <- paste0(args[1:(length(args) - 1)], ",")
392 args[1] <- paste0(prependAtStart, args[1])
393 args[length(args)] <- paste0(args[length(args)], appendAtEnd)
395 argsLength <- length(args)
399 while(index <= argsLength)
404 while(nchar(line) < lineLength && index <= argsLength)
406 line <- paste(line, args[index])
410 argLines <- c(argLines, line)
413 argLines <- unlist(argLines)
414 argLinesLen <- length(argLines)
417 argLines[2:argLinesLen] <- paste0(prependToEachSplit, argLines[2:argLinesLen])