Skip to content

Commit

Permalink
Style package and minor updates (#2)
Browse files Browse the repository at this point in the history
* update package

* update author info

* run styler to fix formatting issues

* add openapitools.json to rbuildignore

* update docs
  • Loading branch information
rcannood authored Nov 11, 2024
1 parent 23e6075 commit c916a16
Show file tree
Hide file tree
Showing 40 changed files with 2,094 additions and 3,018 deletions.
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
^\.\.Rcheck$
^README\.qmd$
^LICENSE\.md$
^openapitools\.json$
2 changes: 1 addition & 1 deletion .openapi-generator/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7.8.0
7.9.0
16 changes: 8 additions & 8 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
Package: laminr.api
Title: R Package Client for the Lamin API
Title: Interface to the 'LaminDB' API
Version: 0.1.0
Authors@R: c(
person("Robrecht", "Cannoodt", , "rcannood@gmail.com", role = c("aut", "cre"),
Authors@R:c(
person("Robrecht", "Cannoodt", email = "robrecht@data-intuitive.com", role = c("aut", "cre"),
comment = c(ORCID = "0000-0003-3641-729X", github = "rcannood")),
person("Luke", "Zappia", , "[email protected]", role = "aut",
comment = c(ORCID = "0000-0001-7744-8565", github = "lazappi"))
person("Luke", "Zappia", email = "[email protected]", role = "aut",
comment = c(ORCID = "0000-0001-7744-8565", github = "lazappi")),
person("Data Intuitive", email = "[email protected]", role = "aut"),
person("Lamin Labs", email = "[email protected]", role = c("aut", "cph"))
)
Description: Client package for accessing the Lamin API. Most content is
generated by the Openapi Generator
https://github.com/openapitools/openapi-generator.
Description: Client package for accessing the Lamin API.
License: Apache License (>= 2)
URL: https://github.com/data-intuitive/laminr.api
BugReports: https://github.com/data-intuitive/laminr.api/issues
Expand Down
176 changes: 104 additions & 72 deletions R/api_client.R
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,7 @@ ApiClient <- R6::R6Class(
self$max_retry_attempts <- max_retry_attempts
}
},
#' Prepare to make an API call with the retry logic.
#'

#' @description
#' Prepare to make an API call with the retry logic.
#'
Expand All @@ -141,29 +140,31 @@ ApiClient <- R6::R6Class(
#' @param body The HTTP request body.
#' @param stream_callback Callback function to process the data stream
#' @param ... Other optional arguments.
#'
#' @return HTTP response
#' @export
CallApi = function(url, method, query_params, header_params, form_params,
file_params, accepts, content_types,
body, stream_callback = NULL, ...) {

resp <- self$Execute(url, method, query_params, header_params,
form_params, file_params,
accepts, content_types,
body, stream_callback = stream_callback, ...)
form_params, file_params,
accepts, content_types,
body,
stream_callback = stream_callback, ...
)

if (is.null(self$max_retry_attempts)) {
self$max_retry_attempts <- 3
}

if (!is.null(self$retry_status_codes)) {

for (i in 1 : self$max_retry_attempts) {
for (i in 1:self$max_retry_attempts) {
if (resp$status_code %in% self$retry_status_codes) {
Sys.sleep((2 ^ i) + stats::runif(n = 1, min = 0, max = 1))
Sys.sleep((2^i) + stats::runif(n = 1, min = 0, max = 1))
resp <- self$Execute(url, method, query_params, header_params,
form_params, file_params, accepts, content_types,
body, stream_callback = stream_callback, ...)
form_params, file_params, accepts, content_types,
body,
stream_callback = stream_callback, ...
)
} else {
break
}
Expand All @@ -172,8 +173,7 @@ ApiClient <- R6::R6Class(

resp
},
#' Make an API call
#'

#' @description
#' Make an API call
#'
Expand All @@ -188,8 +188,8 @@ ApiClient <- R6::R6Class(
#' @param body The HTTP request body.
#' @param stream_callback Callback function to process data stream
#' @param ... Other optional arguments.
#'
#' @return HTTP response
#' @export
Execute = function(url, method, query_params, header_params,
form_params, file_params,
accepts, content_types,
Expand All @@ -202,126 +202,157 @@ ApiClient <- R6::R6Class(
}

# set HTTP accept header
accept = self$select_header(accepts)
accept <- self$select_header(accepts)
if (!is.null(accept)) {
headers['Accept'] = accept
headers["Accept"] <- accept
}

# set HTTP content-type header
content_type = self$select_header(content_types)
content_type <- self$select_header(content_types)
if (!is.null(content_type)) {
headers['Content-Type'] = content_type
headers["Content-Type"] <- content_type
}

if (typeof(stream_callback) == "closure") { # stream data
if (method == "GET") {
httr::GET(url, query = query_params, headers, http_timeout,
httr::user_agent(self$`user_agent`), write_stream(stream_callback), ...)
httr::GET(url,
query = query_params, headers, http_timeout,
httr::user_agent(self$`user_agent`), write_stream(stream_callback), ...
)
} else if (method == "POST") {
httr::POST(url, query = query_params, headers, body = body,
httr::content_type("application/json"), http_timeout,
httr::user_agent(self$`user_agent`), write_stream(stream_callback), ...)
httr::POST(url,
query = query_params, headers, body = body,
httr::content_type("application/json"), http_timeout,
httr::user_agent(self$`user_agent`), write_stream(stream_callback), ...
)
} else if (method == "PUT") {
httr::PUT(url, query = query_params, headers, body = body,
httr::content_type("application/json"), http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), write_stream(stream_callback), ...)
httr::PUT(url,
query = query_params, headers, body = body,
httr::content_type("application/json"), http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), write_stream(stream_callback), ...
)
} else if (method == "PATCH") {
httr::PATCH(url, query = query_params, headers, body = body,
httr::content_type("application/json"), http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), write_stream(stream_callback), ...)
httr::PATCH(url,
query = query_params, headers, body = body,
httr::content_type("application/json"), http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), write_stream(stream_callback), ...
)
} else if (method == "HEAD") {
httr::HEAD(url, query = query_params, headers, http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), write_stream(stream_callback), ...)
httr::HEAD(url,
query = query_params, headers, http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), write_stream(stream_callback), ...
)
} else if (method == "DELETE") {
httr::DELETE(url, query = query_params, headers, http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), write_stream(stream_callback), ...)
httr::DELETE(url,
query = query_params, headers, http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), write_stream(stream_callback), ...
)
} else {
err_msg <- "Http method must be `GET`, `HEAD`, `OPTIONS`, `POST`, `PATCH`, `PUT` or `DELETE`."
rlang::abort(message = err_msg,
.subclass = "ApiException",
ApiException = ApiException$new(status = 0, reason = err_msg))
rlang::abort(
message = err_msg,
.subclass = "ApiException",
ApiException = ApiException$new(status = 0, reason = err_msg)
)
}
} else { # no streaming
if (method == "GET") {
httr_response <- httr::GET(url, query = query_params, headers, http_timeout,
httr::user_agent(self$`user_agent`), ...)
httr_response <- httr::GET(url,
query = query_params, headers, http_timeout,
httr::user_agent(self$`user_agent`), ...
)
} else if (method == "POST") {
httr_response <- httr::POST(url, query = query_params, headers, body = body,
httr::content_type("application/json"), http_timeout,
httr::user_agent(self$`user_agent`), ...)
httr_response <- httr::POST(url,
query = query_params, headers, body = body,
httr::content_type("application/json"), http_timeout,
httr::user_agent(self$`user_agent`), ...
)
} else if (method == "PUT") {
httr_response <- httr::PUT(url, query = query_params, headers, body = body,
httr::content_type("application/json"), http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), ...)
httr_response <- httr::PUT(url,
query = query_params, headers, body = body,
httr::content_type("application/json"), http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), ...
)
} else if (method == "PATCH") {
httr_response <- httr::PATCH(url, query = query_params, headers, body = body,
httr::content_type("application/json"), http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), ...)
httr_response <- httr::PATCH(url,
query = query_params, headers, body = body,
httr::content_type("application/json"), http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), ...
)
} else if (method == "HEAD") {
httr_response <- httr::HEAD(url, query = query_params, headers, http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), ...)
httr_response <- httr::HEAD(url,
query = query_params, headers, http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), ...
)
} else if (method == "DELETE") {
httr_response <- httr::DELETE(url, query = query_params, headers, http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), ...)
httr_response <- httr::DELETE(url,
query = query_params, headers, http_timeout,
http_timeout, httr::user_agent(self$`user_agent`), ...
)
} else {
err_msg <- "Http method must be `GET`, `HEAD`, `OPTIONS`, `POST`, `PATCH`, `PUT` or `DELETE`."
rlang::abort(message = err_msg,
.subclass = "ApiException",
ApiException = ApiException$new(status = 0, reason = err_msg))
rlang::abort(
message = err_msg,
.subclass = "ApiException",
ApiException = ApiException$new(status = 0, reason = err_msg)
)
}

# return ApiResponse
api_response <- ApiResponse$new()
api_response$status_code <- httr::status_code(httr_response)
api_response$status_code <- httr::status_code(httr_response)
api_response$status_code_desc <- httr::http_status(httr_response)$reason
api_response$response <- httr::content(httr_response, "raw")
api_response$headers <- httr::headers(httr_response)

api_response
}
},
#' Deserialize the content of API response to the given type.
#'

#' @description
#' Deserialize the content of API response to the given type.
#'
#' @param raw_response Raw response.
#' @param return_type R return type.
#' @param pkg_env Package environment.
#'
#' @return Deserialized object.
#' @export
deserialize = function(raw_response, return_type, pkg_env) {
resp_obj <- jsonlite::fromJSON(raw_response)
self$deserializeObj(resp_obj, return_type, pkg_env)
},
#' Deserialize the response from jsonlite object based on the given type
#'

#' @description
#' Deserialize the response from jsonlite object based on the given type
#' by handling complex and nested types by iterating recursively
#' Example return_types will be like "array[integer]", "map(Pet)", "array[map(Tag)]", etc.,
#' Example return_types will be like "array[integer]", "map(Pet)",
#' "array[map(Tag)]", etc.,
#'
#' @param obj Response object.
#' @param return_type R return type.
#' @param pkg_env Package environment.
#'
#' @return Deserialized object.
#' @export
deserializeObj = function(obj, return_type, pkg_env) {
return_obj <- NULL
primitive_types <- c("character", "numeric", "integer", "logical", "complex")

# To handle the "map" type
if (startsWith(return_type, "map(")) {
inner_return_type <- regmatches(return_type,
regexec(pattern = "map\\((.*)\\)", return_type))[[1]][2]
inner_return_type <- regmatches(
return_type,
regexec(pattern = "map\\((.*)\\)", return_type)
)[[1]][2]
return_obj <- lapply(names(obj), function(name) {
self$deserializeObj(obj[[name]], inner_return_type, pkg_env)
})
names(return_obj) <- names(obj)
} else if (startsWith(return_type, "array[")) {
# To handle the "array" type
inner_return_type <- regmatches(return_type,
regexec(pattern = "array\\[(.*)\\]", return_type))[[1]][2]
inner_return_type <- regmatches(
return_type,
regexec(pattern = "array\\[(.*)\\]", return_type)
)[[1]][2]
if (c(inner_return_type) %in% primitive_types) {
return_obj <- vector("list", length = length(obj))
if (length(obj) > 0) {
Expand All @@ -334,8 +365,10 @@ ApiClient <- R6::R6Class(
return_obj <- vector("list", length = nrow(obj))
if (nrow(obj) > 0) {
for (row in 1:nrow(obj)) {

Check warning on line 367 in R/api_client.R

View workflow job for this annotation

GitHub Actions / R-CMD-check

file=R/api_client.R,line=367,col=27,[seq_linter] 1:nrow(...) is likely to be wrong in the empty edge case. Use seq_len(nrow(...)) instead.
return_obj[[row]] <- self$deserializeObj(obj[row, , drop = FALSE],
inner_return_type, pkg_env)
return_obj[[row]] <- self$deserializeObj(
obj[row, , drop = FALSE],
inner_return_type, pkg_env
)
}
}
}
Expand Down Expand Up @@ -367,15 +400,14 @@ ApiClient <- R6::R6Class(
}
return_obj
},
#' Return a property header (for accept or content-type).
#'

#' @description
#' Return a property header (for accept or content-type). If JSON-related MIME is found,
#' return it. Otherwise, return the first one, if any.
#'
#' @param headers A list of headers
#'
#' @return A header (e.g. 'application/json')
#' @export
select_header = function(headers) {
if (length(headers) == 0) {
return(invisible(NULL))
Expand Down
10 changes: 3 additions & 7 deletions R/api_exception.R
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,13 @@ ApiException <- R6::R6Class(
reason = NULL,
body = NULL,
headers = NULL,
#' Initialize a new ApiException class.
#'

#' @description
#' Initialize a new ApiExceptino class.
#' Initialize a new ApiException class.
#'
#' @param status HTTP status.
#' @param reason Reason of the ApiException.
#' @param http_response HTTP response object.
#' @export
initialize = function(status = NULL, reason = NULL, http_response = NULL) {
if (!is.null(http_response)) {
self$status <- http_response$status_code
Expand All @@ -47,13 +45,11 @@ ApiException <- R6::R6Class(
self$headers <- NULL
}
},
#' Returns the string format of ApiException.
#'

#' @description
#' Returns the string format of ApiException.
#'
#' @return the string format of ApiException.
#' @export
toString = function() {
errorMsg <- ""
errorMsg <- paste("status : ", self$status, "\n", sep = "")
Expand Down
Loading

0 comments on commit c916a16

Please sign in to comment.