From 3d20af4cba22f0f688e8a7be2e15907dd180ee7e Mon Sep 17 00:00:00 2001 From: danymukesha Date: Tue, 27 Aug 2024 23:54:05 +0200 Subject: [PATCH 01/28] issue #5, Migrate to httr2 on function named request --- R/request.R | 401 +++++++++++++++++++++++++++------------------------- 1 file changed, 211 insertions(+), 190 deletions(-) mode change 100644 => 100755 R/request.R diff --git a/R/request.R b/R/request.R old mode 100644 new mode 100755 index c9fe31a..4a51471 --- a/R/request.R +++ b/R/request.R @@ -1,190 +1,211 @@ -#' Ensembl REST API server -#' -#' @return A string containing Ensembl REST API server URL. -#' @keywords internal -ensembl_server <- function() "https://rest.ensembl.org" - -#' User agent identification -#' -#' Generates an S3 \code{request} object as defined by the package \code{httr}, -#' that is used to identify this package as the user agent in requests to the -#' Ensembl REST API. The user agent identification string is: \code{"ensemblr: R -#' Client for the Ensembl REST API"}. -#' -#' @return An S3 \code{request} object as defined by the package \code{httr}. -#' @keywords internal -user_agent_id <- function() - httr::user_agent("ensemblr: R Client for the Ensembl REST API") - -#' Warn if response errored -#' -#' Warn if an httr \code{\link[httr]{response}} errored. It also returns a tidy -#' warning message. -#' -#' @param response A \code{\link[httr]{response}} object. -#' -#' @return A scalar character vector with a warning message, or the string -#' \code{'OK'} if the response was successful, although this function is -#' called mostly for its side effect, i.e., the triggering of a warning. -#' @keywords internal -warn_when_request_errored <- function(response) { - - code <- httr::status_code(response) - # If status code is 200 (sucessful) then there is nothing to be done in this - # function. - if (identical(code, 200L)) return('OK') - - url <- response$url - type <- httr::http_type(response) - content <- httr::content(response, "text", encoding = 'UTF-8') - - if (identical(type, "application/json")) { - response_msg <- (jsonlite::fromJSON(content, flatten = TRUE))$error - } - else { - content2 <- httr::content(response, as = 'parsed', encoding = 'UTF-8') - if (identical(code, 503L)) { - msg1 <- rvest::html_text(rvest::html_nodes(content2, 'body'), trim = TRUE) - msg2 <- stringr::str_replace(msg1, '\\n', '\\. ') - response_msg <- glue::glue('{msg2}') - } else { - # NB rvest::html_nodes uses only one of the two arguments: css or xpath. - # That is why xpath being missing from the call below is not an issue. - msg1 <- rvest::html_text(rvest::html_nodes(content2, 'h1'), trim = TRUE) - msg2 <- rvest::html_text(rvest::html_nodes(content2, 'h2'), trim = TRUE) - response_msg <- glue::glue('{msg1}. {msg2}.') - } - # TODO: handle 400 error, e.g. resource_url = '/info/variation/populations/homo_sapiens/little humans' - } - - wrn_msg <- glue::glue( - '\n\n', - '* Status code: {code}\n', - '* Server message: {response_msg}\n', - '* Endpoint: {url}') - - warning(wrn_msg, immediate. = TRUE, call. = FALSE) - return(wrn_msg) -} - -#' Request an endpoint from Ensembl REST API -#' -#' Performs a \code{\link[httr]{GET}} request on the endpoint as specified by -#' \code{resource_url}. -#' -#' @param resource_url Endpoint URL. The endpoint is internally appended to the -#' \code{base_url}. It should start with a forward slash (\code{'/'}). -#' @param base_url The Ensembl REST API base URL. -#' @param verbose Whether to be verbose. -#' @param warnings Whether to print warnings. -#' -#' @return A named list of four elements: -#' \describe{ -#' \item{url}{The URL endpoint.} -#' \item{response_code}{\href{https://tinyurl.com/8yqvhwf}{HTTP -#' status code}.} -#' \item{status}{A string describing the status of the response obtained: -#' \code{"OK"} if successful or a description the error.} -#' \item{content}{The parsed JSON as a nested list, as returned by -#' \code{\link[jsonlite]{fromJSON}}.} -#' } -#' -#' @keywords internal -request <- function(resource_url, base_url = ensembl_server(), - verbose = FALSE, warnings = TRUE) { - - if (verbose) message(glue::glue("Base URL: {base_url}.")) - - url <- stringr::str_c(base_url, resource_url) - if (verbose) message(glue::glue("Requesting resource: {url}.")) - - if (verbose) message(glue::glue("Using the user agent: {user_agent_id()$options$useragent}.")) - response <- httr::GET(url, user_agent_id()) - - response_code <- httr::status_code(response) - if (verbose) message(glue::glue("Response code: {response_code}.")) - - # Response object (a list of four elements): - # - url: the resource URL - # - response_code: response code - # - status: short remark about what went wrong with the response, - # or OK if successful. - # - response content: the content of the parsed JSON response, or NULL if - # not successful. - obj <- list(url = url, - response_code = response_code, - status = NA_character_, - content = NULL) - - # If response is not 200, i.e. if request did not complete successfully then - # return an empty response object (NULL) and warn about the response code. - if (!identical(response_code, 200L)) { - wrg_msg <- warn_when_request_errored(response) - obj$status <- wrg_msg - return(obj) - } else {# Else response code is 200 and we move on to JSON parsing. - - # Check if the content type of the response is JSON. - content_type <- httr::http_type(response) - if (verbose) message(glue::glue("Response content type: {content_type}.")) - - if (!identical(content_type, "application/json")) { - if (warnings) { - wrg_msg <- glue::glue("Response to {url} did not return JSON!") - warning(wrg_msg, immediate. = TRUE, call. = FALSE) - } - obj$status <- "Response content was not application/json." - return(obj) - } - - # Parse JSON content - content <- jsonlite::fromJSON(httr::content(response, "text", encoding = 'UTF-8'), flatten = FALSE) - - obj$status <- "OK" - obj$content <- content - return(obj) - } -} - -#' Parallel version of request -#' -#' Performs a \code{\link[httr]{GET}} request on each of the endpoints as -#' specified by \code{resource_urls}. -#' -#' @param resource_urls Vector of endpoint URLs. Each endpoint is internally -#' appended to the \code{base_url}. It should start with a forward slash -#' (\code{'/'}). -#' @param verbose Whether to be verbose. -#' @param warnings Whether to print warnings. -#' @param progress_bar Whether to show a progress bar. -#' -#' @return A list of named lists of four elements: -#' \describe{ -#' \item{url}{The URL endpoint.} -#' \item{response_code}{\href{https://tinyurl.com/8yqvhwf}{HTTP -#' status code}.} -#' \item{status}{A string describing the status of the response obtained: -#' \code{"OK"} if successful or a description the error.} -#' \item{content}{The parsed JSON as a nested list, as returned by -#' \code{\link[jsonlite]{fromJSON}}.} -#' } -#' -#' @keywords internal -request_parallel <- function(resource_urls, - verbose = FALSE, - warnings = TRUE, - progress_bar = TRUE) { - - - # Usually we'd use purrr::map here but we opted for plyr::llply - # for a no frills alternative with progress bar support. - progress <- dplyr::if_else(progress_bar && interactive(), 'text', 'none') - responses <- plyr::llply( - .data = resource_urls, - .fun = request, - verbose = verbose, - warnings = warnings, - .progress = progress) - - return(responses) -} +#' Ensembl REST API server +#' +#' @return A string containing Ensembl REST API server URL. +#' @keywords internal +ensembl_server <- function() "https://rest.ensembl.org" + +#' User agent identification +#' +#' Generates an S3 \code{request} object as defined by the package \code{httr}, +#' that is used to identify this package as the user agent in requests to the +#' Ensembl REST API. The user agent identification string is: \code{"ensemblr: R +#' Client for the Ensembl REST API"}. +#' +#' @return An S3 \code{request} object as defined by the package \code{httr}. +#' @keywords internal +user_agent_id <- function() + httr::user_agent("ensemblr: R Client for the Ensembl REST API") + +#' Warn if response errored +#' +#' Warn if an httr \code{\link[httr]{response}} errored. It also returns a tidy +#' warning message. +#' +#' @param response A \code{\link[httr]{response}} object. +#' +#' @return A scalar character vector with a warning message, or the string +#' \code{'OK'} if the response was successful, although this function is +#' called mostly for its side effect, i.e., the triggering of a warning. +#' @keywords internal +warn_when_request_errored <- function(response) { + + ## code <- httr::status_code(response) + code <- response |> + httr2::resp_status() + # If status code is 200 (sucessful) then there is nothing to be done in this + # function. + if (identical(code, 200L)) return('OK') # Until here everything seem to be OK. + + #------------------- I HAVE TO CHECK WELL THIS ERROR HANDLING --------------# + url <- response$url + type <- response |> + httr2::resp_content_type() + content <- httr::content(response, "text", encoding = 'UTF-8') + + if (identical(type, "application/json")) { + response_msg <- (jsonlite::fromJSON(content, flatten = TRUE))$error + } + else { + content2 <- httr::content(response, as = 'parsed', encoding = 'UTF-8') + if (identical(code, 503L)) { + msg1 <- rvest::html_text(rvest::html_nodes(content2, 'body'), trim = TRUE) + msg2 <- stringr::str_replace(msg1, '\\n', '\\. ') + response_msg <- glue::glue('{msg2}') + } else { + # NB rvest::html_nodes uses only one of the two arguments: css or xpath. + # That is why xpath being missing from the call below is not an issue. + msg1 <- rvest::html_text(rvest::html_nodes(content2, 'h1'), trim = TRUE) + msg2 <- rvest::html_text(rvest::html_nodes(content2, 'h2'), trim = TRUE) + response_msg <- glue::glue('{msg1}. {msg2}.') + } + # TODO: handle 400 error, e.g. resource_url = '/info/variation/populations/homo_sapiens/little humans' + } + #------------------- I HAVE TO CHECK WELL THIS ERROR HANDLING --------------# + + wrn_msg <- glue::glue( + '\n\n', + '* Status code: {code}\n', + '* Server message: {response_msg}\n', + '* Endpoint: {url}') + + warning(wrn_msg, immediate. = TRUE, call. = FALSE) + return(wrn_msg) +} + +#' Request an endpoint from Ensembl REST API +#' +#' Performs a \code{\link[httr]{GET}} request on the endpoint as specified by +#' \code{resource_url}. +#' +#' @param resource_url Endpoint URL. The endpoint is internally appended to the +#' \code{base_url}. It should start with a forward slash (\code{'/'}). +#' @param base_url The Ensembl REST API base URL. +#' @param verbose Whether to be verbose. +#' @param warnings Whether to print warnings. +#' +#' @return A named list of four elements: +#' \describe{ +#' \item{url}{The URL endpoint.} +#' \item{response_code}{\href{https://tinyurl.com/8yqvhwf}{HTTP +#' status code}.} +#' \item{status}{A string describing the status of the response obtained: +#' \code{"OK"} if successful or a description the error.} +#' \item{content}{The parsed JSON as a nested list, as returned by +#' \code{\link[jsonlite]{fromJSON}}.} +#' } +#' +#' @keywords internal +request <- function(resource_url, base_url = ensembl_server(), + verbose = FALSE, warnings = TRUE) { + + if (verbose) message(glue::glue("Base URL: {base_url}.")) + + url <- stringr::str_c(base_url, resource_url) + if (verbose) message(glue::glue("Requesting resource: {url}.")) + + if (verbose) message(glue::glue("Using the user agent: {user_agent_id()$options$useragent}.")) + # Start switching to httr2 + # Creating a 'request', I opted directly for `json` content from the response instead of text! + req <- httr2::request(base_url = url) |> + httr2::req_headers( + Accept = "application/json" # To avoid + ) + ## response <- httr::GET(url, user_agent_id()) + response <- req |> + httr2::req_user_agent("ensemblr: R Client for the Ensembl REST API") |> + httr2::req_perform() + + ## response_code <- httr::status_code(response) + response_code <- response |> + httr2::resp_status() + if (verbose) message(glue::glue("Response code: {response_code}.")) + + # Response object (a list of four elements): + # - url: the resource URL + # - response_code: response code + # - status: short remark about what went wrong with the response, + # or OK if successful. + # - response content: the content of the parsed JSON response, or NULL if + # not successful. + obj <- list(url = url, + response_code = response_code, + status = NA_character_, + content = NULL) + + # If response is not 200, i.e. if request did not complete successfully then + # return an empty response object (NULL) and warn about the response code. + if (!identical(response_code, 200L)) { + wrg_msg <- warn_when_request_errored(response) + obj$status <- wrg_msg + return(obj) + } else {# Else response code is 200 and we move on to JSON parsing. + + # Check if the content type of the response is JSON. + ## content_type <- httr::http_type(response) + content_type <- response |> + httr2::resp_content_type() + if (verbose) message(glue::glue("Response content type: {content_type}.")) + + if (!identical(content_type, "application/json")) { + if (warnings) { + wrg_msg <- glue::glue("Response to {url} did not return JSON!") + warning(wrg_msg, immediate. = TRUE, call. = FALSE) + } + obj$status <- "Response content was not application/json." + return(obj) + } + + # Parse JSON content + ## content <- jsonlite::fromJSON(httr::content(response, "text", encoding = 'UTF-8'), flatten = FALSE) + content <- response |> + httr2::resp_body_json() |> + data.frame() # should we keep `data.frame` as it was before??? + + obj$status <- "OK" # Shouldn't we take the actual value provided by the response??? + obj$content <- content + return(obj) + } +} + +#' Parallel version of request +#' +#' Performs a \code{\link[httr]{GET}} request on each of the endpoints as +#' specified by \code{resource_urls}. +#' +#' @param resource_urls Vector of endpoint URLs. Each endpoint is internally +#' appended to the \code{base_url}. It should start with a forward slash +#' (\code{'/'}). +#' @param verbose Whether to be verbose. +#' @param warnings Whether to print warnings. +#' @param progress_bar Whether to show a progress bar. +#' +#' @return A list of named lists of four elements: +#' \describe{ +#' \item{url}{The URL endpoint.} +#' \item{response_code}{\href{https://tinyurl.com/8yqvhwf}{HTTP +#' status code}.} +#' \item{status}{A string describing the status of the response obtained: +#' \code{"OK"} if successful or a description the error.} +#' \item{content}{The parsed JSON as a nested list, as returned by +#' \code{\link[jsonlite]{fromJSON}}.} +#' } +#' +#' @keywords internal +request_parallel <- function(resource_urls, + verbose = FALSE, + warnings = TRUE, + progress_bar = TRUE) { + + + # Usually we'd use purrr::map here but we opted for plyr::llply + # for a no frills alternative with progress bar support. + progress <- dplyr::if_else(progress_bar && interactive(), 'text', 'none') + responses <- plyr::llply( + .data = resource_urls, + .fun = request, + verbose = verbose, + warnings = warnings, + .progress = progress) + + return(responses) +} From fd78bb323ac7b4e673b9d157f2f9c04d7195b4ab Mon Sep 17 00:00:00 2001 From: danymukesha Date: Wed, 28 Aug 2024 08:57:35 +0200 Subject: [PATCH 02/28] issue #5, Put in evidence lines to be deprecated or removed --- R/request.R | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/R/request.R b/R/request.R index 4a51471..8975c86 100755 --- a/R/request.R +++ b/R/request.R @@ -29,7 +29,7 @@ user_agent_id <- function() #' @keywords internal warn_when_request_errored <- function(response) { - ## code <- httr::status_code(response) + ## code <- httr::status_code(response) #TO BE DEPRECATED/REMOVED code <- response |> httr2::resp_status() # If status code is 200 (sucessful) then there is nothing to be done in this @@ -110,14 +110,14 @@ request <- function(resource_url, base_url = ensembl_server(), httr2::req_headers( Accept = "application/json" # To avoid ) - ## response <- httr::GET(url, user_agent_id()) + ## response <- httr::GET(url, user_agent_id()) #TO BE DEPRECATED/REMOVED response <- req |> httr2::req_user_agent("ensemblr: R Client for the Ensembl REST API") |> httr2::req_perform() - ## response_code <- httr::status_code(response) + ## response_code <- httr::status_code(response) #TO BE DEPRECATED/REMOVED response_code <- response |> - httr2::resp_status() + httr2::resp_status() # We can also obtain the response code by simply `response$status_code` if (verbose) message(glue::glue("Response code: {response_code}.")) # Response object (a list of four elements): @@ -141,7 +141,7 @@ request <- function(resource_url, base_url = ensembl_server(), } else {# Else response code is 200 and we move on to JSON parsing. # Check if the content type of the response is JSON. - ## content_type <- httr::http_type(response) + ## content_type <- httr::http_type(response) #TO BE DEPRECATED/REMOVED content_type <- response |> httr2::resp_content_type() if (verbose) message(glue::glue("Response content type: {content_type}.")) @@ -156,7 +156,7 @@ request <- function(resource_url, base_url = ensembl_server(), } # Parse JSON content - ## content <- jsonlite::fromJSON(httr::content(response, "text", encoding = 'UTF-8'), flatten = FALSE) + ## content <- jsonlite::fromJSON(httr::content(response, "text", encoding = 'UTF-8'), flatten = FALSE) #TO BE DEPRECATED/REMOVED content <- response |> httr2::resp_body_json() |> data.frame() # should we keep `data.frame` as it was before??? From 034bed28adafdf13e48c6763d814167de85a010a Mon Sep 17 00:00:00 2001 From: Ramiro Magno Date: Sun, 1 Sep 2024 17:56:19 +0100 Subject: [PATCH 03/28] Add tmp dir --- .Rbuildignore | 1 + .gitignore | 1 + 2 files changed, 2 insertions(+) diff --git a/.Rbuildignore b/.Rbuildignore index 674edf6..5e74ab2 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -9,3 +9,4 @@ ^pkgdown$ ^\.travis\.yml$ ^\.github$ +^tmp$ diff --git a/.gitignore b/.gitignore index 4fb4af4..3fa650d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ inst/doc docs/ docs +tmp/ From fc07cd5a0ebc2b9127c77d784eba53783cc834d4 Mon Sep 17 00:00:00 2001 From: Ramiro Magno Date: Sun, 1 Sep 2024 18:09:00 +0100 Subject: [PATCH 04/28] Cleaning up --- R/request.R | 313 ++++++++++------------------------------------------ 1 file changed, 59 insertions(+), 254 deletions(-) diff --git a/R/request.R b/R/request.R index 62ee581..0acbabd 100755 --- a/R/request.R +++ b/R/request.R @@ -1,216 +1,3 @@ -<<<<<<< HEAD -#' Ensembl REST API server -#' -#' @return A string containing Ensembl REST API server URL. -#' @keywords internal -ensembl_server <- function() "https://rest.ensembl.org" - -#' User agent identification -#' -#' Generates an S3 \code{request} object as defined by the package \code{httr}, -#' that is used to identify this package as the user agent in requests to the -#' Ensembl REST API. The user agent identification string is: \code{"ensemblr: R -#' Client for the Ensembl REST API"}. -#' -#' @return An S3 \code{request} object as defined by the package \code{httr}. -#' @keywords internal -user_agent_id <- function() - httr::user_agent("ensemblr: R Client for the Ensembl REST API") - -#' Warn if response errored -#' -#' Warn if an httr \code{\link[httr]{response}} errored. It also returns a tidy -#' warning message. -#' -#' @param response A \code{\link[httr]{response}} object. -#' -#' @return A scalar character vector with a warning message, or the string -#' \code{'OK'} if the response was successful, although this function is -#' called mostly for its side effect, i.e., the triggering of a warning. -#' @keywords internal -warn_when_request_errored <- function(response) { - - ## code <- httr::status_code(response) #TO BE DEPRECATED/REMOVED - code <- response |> - httr2::resp_status() - # If status code is 200 (sucessful) then there is nothing to be done in this - # function. - if (identical(code, 200L)) return('OK') # Until here everything seem to be OK. - - #------------------- I HAVE TO CHECK WELL THIS ERROR HANDLING --------------# - url <- response$url - type <- response |> - httr2::resp_content_type() - content <- httr::content(response, "text", encoding = 'UTF-8') - - if (identical(type, "application/json")) { - response_msg <- (jsonlite::fromJSON(content, flatten = TRUE))$error - } - else { - content2 <- httr::content(response, as = 'parsed', encoding = 'UTF-8') - if (identical(code, 503L)) { - msg1 <- rvest::html_text(rvest::html_nodes(content2, 'body'), trim = TRUE) - msg2 <- stringr::str_replace(msg1, '\\n', '\\. ') - response_msg <- glue::glue('{msg2}') - } else { - # NB rvest::html_nodes uses only one of the two arguments: css or xpath. - # That is why xpath being missing from the call below is not an issue. - msg1 <- rvest::html_text(rvest::html_nodes(content2, 'h1'), trim = TRUE) - msg2 <- rvest::html_text(rvest::html_nodes(content2, 'h2'), trim = TRUE) - response_msg <- glue::glue('{msg1}. {msg2}.') - } - # TODO: handle 400 error, e.g. resource_url = '/info/variation/populations/homo_sapiens/little humans' - } - #------------------- I HAVE TO CHECK WELL THIS ERROR HANDLING --------------# - - wrn_msg <- glue::glue( - '\n\n', - '* Status code: {code}\n', - '* Server message: {response_msg}\n', - '* Endpoint: {url}') - - warning(wrn_msg, immediate. = TRUE, call. = FALSE) - return(wrn_msg) -} - -#' Request an endpoint from Ensembl REST API -#' -#' Performs a \code{\link[httr]{GET}} request on the endpoint as specified by -#' \code{resource_url}. -#' -#' @param resource_url Endpoint URL. The endpoint is internally appended to the -#' \code{base_url}. It should start with a forward slash (\code{'/'}). -#' @param base_url The Ensembl REST API base URL. -#' @param verbose Whether to be verbose. -#' @param warnings Whether to print warnings. -#' -#' @return A named list of four elements: -#' \describe{ -#' \item{url}{The URL endpoint.} -#' \item{response_code}{\href{https://tinyurl.com/8yqvhwf}{HTTP -#' status code}.} -#' \item{status}{A string describing the status of the response obtained: -#' \code{"OK"} if successful or a description the error.} -#' \item{content}{The parsed JSON as a nested list, as returned by -#' \code{\link[jsonlite]{fromJSON}}.} -#' } -#' -#' @keywords internal -request <- function(resource_url, base_url = ensembl_server(), - verbose = FALSE, warnings = TRUE) { - - if (verbose) message(glue::glue("Base URL: {base_url}.")) - - url <- stringr::str_c(base_url, resource_url) - if (verbose) message(glue::glue("Requesting resource: {url}.")) - - if (verbose) message(glue::glue("Using the user agent: {user_agent_id()$options$useragent}.")) - # Start switching to httr2 - # Creating a 'request', I opted directly for `json` content from the response instead of text! - req <- httr2::request(base_url = url) |> - httr2::req_headers( - Accept = "application/json" # To avoid - ) - ## response <- httr::GET(url, user_agent_id()) #TO BE DEPRECATED/REMOVED - response <- req |> - httr2::req_user_agent("ensemblr: R Client for the Ensembl REST API") |> - httr2::req_perform() - - ## response_code <- httr::status_code(response) #TO BE DEPRECATED/REMOVED - response_code <- response |> - httr2::resp_status() # We can also obtain the response code by simply `response$status_code` - if (verbose) message(glue::glue("Response code: {response_code}.")) - - # Response object (a list of four elements): - # - url: the resource URL - # - response_code: response code - # - status: short remark about what went wrong with the response, - # or OK if successful. - # - response content: the content of the parsed JSON response, or NULL if - # not successful. - obj <- list(url = url, - response_code = response_code, - status = NA_character_, - content = NULL) - - # If response is not 200, i.e. if request did not complete successfully then - # return an empty response object (NULL) and warn about the response code. - if (!identical(response_code, 200L)) { - wrg_msg <- warn_when_request_errored(response) - obj$status <- wrg_msg - return(obj) - } else {# Else response code is 200 and we move on to JSON parsing. - - # Check if the content type of the response is JSON. - ## content_type <- httr::http_type(response) #TO BE DEPRECATED/REMOVED - content_type <- response |> - httr2::resp_content_type() - if (verbose) message(glue::glue("Response content type: {content_type}.")) - - if (!identical(content_type, "application/json")) { - if (warnings) { - wrg_msg <- glue::glue("Response to {url} did not return JSON!") - warning(wrg_msg, immediate. = TRUE, call. = FALSE) - } - obj$status <- "Response content was not application/json." - return(obj) - } - - # Parse JSON content - ## content <- jsonlite::fromJSON(httr::content(response, "text", encoding = 'UTF-8'), flatten = FALSE) #TO BE DEPRECATED/REMOVED - content <- response |> - httr2::resp_body_json() |> - data.frame() # should we keep `data.frame` as it was before??? - - obj$status <- "OK" # Shouldn't we take the actual value provided by the response??? - obj$content <- content - return(obj) - } -} - -#' Parallel version of request -#' -#' Performs a \code{\link[httr]{GET}} request on each of the endpoints as -#' specified by \code{resource_urls}. -#' -#' @param resource_urls Vector of endpoint URLs. Each endpoint is internally -#' appended to the \code{base_url}. It should start with a forward slash -#' (\code{'/'}). -#' @param verbose Whether to be verbose. -#' @param warnings Whether to print warnings. -#' @param progress_bar Whether to show a progress bar. -#' -#' @return A list of named lists of four elements: -#' \describe{ -#' \item{url}{The URL endpoint.} -#' \item{response_code}{\href{https://tinyurl.com/8yqvhwf}{HTTP -#' status code}.} -#' \item{status}{A string describing the status of the response obtained: -#' \code{"OK"} if successful or a description the error.} -#' \item{content}{The parsed JSON as a nested list, as returned by -#' \code{\link[jsonlite]{fromJSON}}.} -#' } -#' -#' @keywords internal -request_parallel <- function(resource_urls, - verbose = FALSE, - warnings = TRUE, - progress_bar = TRUE) { - - - # Usually we'd use purrr::map here but we opted for plyr::llply - # for a no frills alternative with progress bar support. - progress <- dplyr::if_else(progress_bar && interactive(), 'text', 'none') - responses <- plyr::llply( - .data = resource_urls, - .fun = request, - verbose = verbose, - warnings = warnings, - .progress = progress) - - return(responses) -} -======= #' Ensembl REST API server #' #' @return A string containing Ensembl REST API server URL. @@ -226,9 +13,8 @@ ensembl_server <- function() "https://rest.ensembl.org" #' #' @return An S3 \code{request} object as defined by the package \code{httr}. #' @keywords internal -user_agent <- function() { +user_agent_id <- function() httr::user_agent("ensemblr (https://www.pattern.institute/ensemblr)") -} #' Warn if response errored #' @@ -242,41 +28,45 @@ user_agent <- function() { #' called mostly for its side effect, i.e., the triggering of a warning. #' @keywords internal warn_when_request_errored <- function(response) { - code <- httr::status_code(response) + + ## code <- httr::status_code(response) #TO BE DEPRECATED/REMOVED + code <- response |> + httr2::resp_status() # If status code is 200 (sucessful) then there is nothing to be done in this # function. - if (identical(code, 200L)) { - return("OK") - } + if (identical(code, 200L)) return('OK') # Until here everything seem to be OK. + #------------------- I HAVE TO CHECK WELL THIS ERROR HANDLING --------------# url <- response$url - type <- httr::http_type(response) - content <- httr::content(response, "text", encoding = "UTF-8") + type <- response |> + httr2::resp_content_type() + content <- httr::content(response, "text", encoding = 'UTF-8') if (identical(type, "application/json")) { response_msg <- (jsonlite::fromJSON(content, flatten = TRUE))$error - } else { - content2 <- httr::content(response, as = "parsed", encoding = "UTF-8") + } + else { + content2 <- httr::content(response, as = 'parsed', encoding = 'UTF-8') if (identical(code, 503L)) { - msg1 <- rvest::html_text(rvest::html_nodes(content2, "body"), trim = TRUE) - msg2 <- stringr::str_replace(msg1, "\\n", "\\. ") - response_msg <- glue::glue("{msg2}") + msg1 <- rvest::html_text(rvest::html_nodes(content2, 'body'), trim = TRUE) + msg2 <- stringr::str_replace(msg1, '\\n', '\\. ') + response_msg <- glue::glue('{msg2}') } else { - # NB rvest::html_nodes uses only one of the two arguments: css or xpath. - # That is why xpath being missing from the call below is not an issue. - msg1 <- rvest::html_text(rvest::html_nodes(content2, "h1"), trim = TRUE) - msg2 <- rvest::html_text(rvest::html_nodes(content2, "h2"), trim = TRUE) - response_msg <- glue::glue("{msg1}. {msg2}.") + # NB rvest::html_nodes uses only one of the two arguments: css or xpath. + # That is why xpath being missing from the call below is not an issue. + msg1 <- rvest::html_text(rvest::html_nodes(content2, 'h1'), trim = TRUE) + msg2 <- rvest::html_text(rvest::html_nodes(content2, 'h2'), trim = TRUE) + response_msg <- glue::glue('{msg1}. {msg2}.') } # TODO: handle 400 error, e.g. resource_url = '/info/variation/populations/homo_sapiens/little humans' } + #------------------- I HAVE TO CHECK WELL THIS ERROR HANDLING --------------# wrn_msg <- glue::glue( - "\n\n", - "* Status code: {code}\n", - "* Server message: {response_msg}\n", - "* Endpoint: {url}" - ) + '\n\n', + '* Status code: {code}\n', + '* Server message: {response_msg}\n', + '* Endpoint: {url}') warning(wrn_msg, immediate. = TRUE, call. = FALSE) return(wrn_msg) @@ -306,16 +96,28 @@ warn_when_request_errored <- function(response) { #' #' @keywords internal request <- function(resource_url, base_url = ensembl_server(), - verbose = FALSE, warnings = TRUE) { + verbose = FALSE, warnings = TRUE) { + if (verbose) message(glue::glue("Base URL: {base_url}.")) url <- stringr::str_c(base_url, resource_url) if (verbose) message(glue::glue("Requesting resource: {url}.")) if (verbose) message(glue::glue("Using the user agent: {user_agent_id()$options$useragent}.")) - response <- httr::GET(url, user_agent()) - - response_code <- httr::status_code(response) + # Start switching to httr2 + # Creating a 'request', I opted directly for `json` content from the response instead of text! + req <- httr2::request(base_url = url) |> + httr2::req_headers( + Accept = "application/json" # To avoid + ) + ## response <- httr::GET(url, user_agent_id()) #TO BE DEPRECATED/REMOVED + response <- req |> + httr2::req_user_agent("ensemblr: R Client for the Ensembl REST API") |> + httr2::req_perform() + + ## response_code <- httr::status_code(response) #TO BE DEPRECATED/REMOVED + response_code <- response |> + httr2::resp_status() # We can also obtain the response code by simply `response$status_code` if (verbose) message(glue::glue("Response code: {response_code}.")) # Response object (a list of four elements): @@ -325,12 +127,10 @@ request <- function(resource_url, base_url = ensembl_server(), # or OK if successful. # - response content: the content of the parsed JSON response, or NULL if # not successful. - obj <- list( - url = url, - response_code = response_code, - status = NA_character_, - content = NULL - ) + obj <- list(url = url, + response_code = response_code, + status = NA_character_, + content = NULL) # If response is not 200, i.e. if request did not complete successfully then # return an empty response object (NULL) and warn about the response code. @@ -338,10 +138,12 @@ request <- function(resource_url, base_url = ensembl_server(), wrg_msg <- warn_when_request_errored(response) obj$status <- wrg_msg return(obj) - } else { # Else response code is 200 and we move on to JSON parsing. + } else {# Else response code is 200 and we move on to JSON parsing. # Check if the content type of the response is JSON. - content_type <- httr::http_type(response) + ## content_type <- httr::http_type(response) #TO BE DEPRECATED/REMOVED + content_type <- response |> + httr2::resp_content_type() if (verbose) message(glue::glue("Response content type: {content_type}.")) if (!identical(content_type, "application/json")) { @@ -354,9 +156,12 @@ request <- function(resource_url, base_url = ensembl_server(), } # Parse JSON content - content <- jsonlite::fromJSON(httr::content(response, "text", encoding = "UTF-8"), flatten = FALSE) + ## content <- jsonlite::fromJSON(httr::content(response, "text", encoding = 'UTF-8'), flatten = FALSE) #TO BE DEPRECATED/REMOVED + content <- response |> + httr2::resp_body_json() |> + data.frame() # should we keep `data.frame` as it was before??? - obj$status <- "OK" + obj$status <- "OK" # Shouldn't we take the actual value provided by the response??? obj$content <- content return(obj) } @@ -390,17 +195,17 @@ request_parallel <- function(resource_urls, verbose = FALSE, warnings = TRUE, progress_bar = TRUE) { + + # Usually we'd use purrr::map here but we opted for plyr::llply # for a no frills alternative with progress bar support. - progress <- dplyr::if_else(progress_bar && interactive(), "text", "none") + progress <- dplyr::if_else(progress_bar && interactive(), 'text', 'none') responses <- plyr::llply( .data = resource_urls, .fun = request, verbose = verbose, warnings = warnings, - .progress = progress - ) + .progress = progress) return(responses) } ->>>>>>> main From 294726615b5f2fb052e6535534c9fa127ee2be15 Mon Sep 17 00:00:00 2001 From: Ramiro Magno Date: Sun, 1 Sep 2024 22:53:43 +0100 Subject: [PATCH 05/28] Add functions `req()` and `reqs()` --- NAMESPACE | 1 - R/req.R | 68 +++++++++++++++++++++++++++++++++++++++++ man/ensemblr-package.Rd | 11 +++---- 3 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 R/req.R diff --git a/NAMESPACE b/NAMESPACE index 7ae2656..5e49a59 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -28,6 +28,5 @@ export(get_xrefs_by_ensembl_id) export(get_xrefs_by_gene) export(is_ensembl_reachable) importFrom(magrittr,"%>%") -importFrom(memoise,memoise) importFrom(rlang,.data) importFrom(tibble,tibble) diff --git a/R/req.R b/R/req.R new file mode 100644 index 0000000..c39a65d --- /dev/null +++ b/R/req.R @@ -0,0 +1,68 @@ +vars_in_braces <- function(x) { + matches <- stringr::str_extract_all(x, "\\{([^}]+)\\}") + vars <- gsub("[{}]", "", unlist(matches)) + + vars +} + +base_url <- function() "https://rest.ensembl.org" + +user_agent <- function() "ensemblr (https://www.pattern.institute/ensemblr)" + +# Example: +# +# req("/cafe/genetree/member/symbol/{species}/{symbol}", species = "homo_sapiens", symbol = "BRCA2") |> +# httr2::req_perform() |> +# httr2::resp_body_json() +req <- + function(res, + ..., + .body = NULL, + .type = 'application/json') { + + # All parameters. + params <- list(...) + pnames <- names(params) + + # Required parameters. + req_pnames <- vars_in_braces(res) + req_params <- params[req_pnames] + + # Optional parameters. + opt_pnames <- setdiff(pnames, req_pnames) + opt_params <- params[opt_pnames] + + res <- glue::glue(res, .envir = as.environment(req_params)) + + req <- + httr2::request(base_url()) |> + httr2::req_url_path_append(res) |> + httr2::req_url_query(!!!opt_params) |> + httr2::req_headers(Accept = .type) |> + httr2::req_user_agent(user_agent()) + + if (!is.null(.body)) { + req <- httr2::req_body_raw(req, body = .body, type = .type) + } + + req + } + +reqs <- function(res, + ..., + .body = NULL, + .type = 'application/json') { + params <- list(...) + .body <- .body %||% list(.body) + + req_args <- + vctrs::vec_recycle_common( + res = res, + !!!params, + .body = .body, + .type = .type + ) + reqs <- purrr::pmap(.l = req_args, .f = req) + + reqs +} diff --git a/man/ensemblr-package.Rd b/man/ensemblr-package.Rd index 1f28765..1da7fa0 100644 --- a/man/ensemblr-package.Rd +++ b/man/ensemblr-package.Rd @@ -6,16 +6,14 @@ \alias{ensemblr-package} \title{ensemblr: R Client for the Ensembl REST API} \description{ -\if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} - R Client for the Ensembl REST API. } \seealso{ Useful links: \itemize{ - \item \url{https://github.com/ramiromagno/ensemblr} - \item \url{http://rmagno.eu/ensemblr/} - \item Report bugs at \url{https://github.com/ramiromagno/ensemblr/issues} + \item \url{https://github.com/patterninstitute/ensemblr} + \item \url{https://www.pattern.institute/ensemblr/} + \item Report bugs at \url{https://github.com/patterninstitute/ensemblr/issues} } } @@ -24,13 +22,14 @@ Useful links: Authors: \itemize{ + \item Dany Mukesha \email{dmukesha@pattern.institute} (\href{https://orcid.org/0009-0001-9514-751X}{ORCID}) \item Isabel Duarte \email{iduarte.scientist@gmail.com} (\href{https://orcid.org/0000-0003-0060-2936}{ORCID}) \item Ana-Teresa Maia \email{maia.anateresa@gmail.com} (\href{https://orcid.org/0000-0002-0454-9207}{ORCID}) } Other contributors: \itemize{ - \item CINTESIS [copyright holder, funder] + \item CINTESIS [funder] \item Pattern Institute [copyright holder, funder] } From ff447954d50f4d6bc6da1c0fdd1ceed14d0009d0 Mon Sep 17 00:00:00 2001 From: Ramiro Magno Date: Mon, 2 Sep 2024 11:21:21 +0100 Subject: [PATCH 06/28] Add basic tests --- tests/testthat.R | 12 ++++++++++++ tests/testthat/test-ensembl-server.R | 3 +++ tests/testthat/test-user-agent-id.R | 4 ++++ 3 files changed, 19 insertions(+) create mode 100644 tests/testthat.R create mode 100644 tests/testthat/test-ensembl-server.R create mode 100644 tests/testthat/test-user-agent-id.R diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..cb002db --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,12 @@ +# This file is part of the standard setup for testthat. +# It is recommended that you do not modify it. +# +# Where should you do additional test configuration? +# Learn more about the roles of various files in: +# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview +# * https://testthat.r-lib.org/articles/special-files.html + +library(testthat) +library(ensemblr) + +test_check("ensemblr") diff --git a/tests/testthat/test-ensembl-server.R b/tests/testthat/test-ensembl-server.R new file mode 100644 index 0000000..9e4f0f2 --- /dev/null +++ b/tests/testthat/test-ensembl-server.R @@ -0,0 +1,3 @@ +test_that("ensembl_server() works", { + expect_equal(ensembl_server(), "https://rest.ensembl.org") +}) diff --git a/tests/testthat/test-user-agent-id.R b/tests/testthat/test-user-agent-id.R new file mode 100644 index 0000000..4a1f764 --- /dev/null +++ b/tests/testthat/test-user-agent-id.R @@ -0,0 +1,4 @@ +test_that("user_agent_id() works", { + user_agent_desc <- "ensemblr (https://www.pattern.institute/ensemblr)" + expect_equal(user_agent_id(), user_agent_desc) +}) From d2a1d61e6e20ca56ff6c9313a0f411f7c8b8ae8f Mon Sep 17 00:00:00 2001 From: danymukesha Date: Thu, 5 Sep 2024 08:09:29 +0200 Subject: [PATCH 07/28] add helper functions for http headers --- R/req.R | 193 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 125 insertions(+), 68 deletions(-) mode change 100644 => 100755 R/req.R diff --git a/R/req.R b/R/req.R old mode 100644 new mode 100755 index c39a65d..5bae582 --- a/R/req.R +++ b/R/req.R @@ -1,68 +1,125 @@ -vars_in_braces <- function(x) { - matches <- stringr::str_extract_all(x, "\\{([^}]+)\\}") - vars <- gsub("[{}]", "", unlist(matches)) - - vars -} - -base_url <- function() "https://rest.ensembl.org" - -user_agent <- function() "ensemblr (https://www.pattern.institute/ensemblr)" - -# Example: -# -# req("/cafe/genetree/member/symbol/{species}/{symbol}", species = "homo_sapiens", symbol = "BRCA2") |> -# httr2::req_perform() |> -# httr2::resp_body_json() -req <- - function(res, - ..., - .body = NULL, - .type = 'application/json') { - - # All parameters. - params <- list(...) - pnames <- names(params) - - # Required parameters. - req_pnames <- vars_in_braces(res) - req_params <- params[req_pnames] - - # Optional parameters. - opt_pnames <- setdiff(pnames, req_pnames) - opt_params <- params[opt_pnames] - - res <- glue::glue(res, .envir = as.environment(req_params)) - - req <- - httr2::request(base_url()) |> - httr2::req_url_path_append(res) |> - httr2::req_url_query(!!!opt_params) |> - httr2::req_headers(Accept = .type) |> - httr2::req_user_agent(user_agent()) - - if (!is.null(.body)) { - req <- httr2::req_body_raw(req, body = .body, type = .type) - } - - req - } - -reqs <- function(res, - ..., - .body = NULL, - .type = 'application/json') { - params <- list(...) - .body <- .body %||% list(.body) - - req_args <- - vctrs::vec_recycle_common( - res = res, - !!!params, - .body = .body, - .type = .type - ) - reqs <- purrr::pmap(.l = req_args, .f = req) - - reqs -} +vars_in_braces <- function(x) { + matches <- stringr::str_extract_all(x, "\\{([^}]+)\\}") + vars <- gsub("[{}]", "", unlist(matches)) + + vars +} + +# Helper functions for http headers +# The reference to which headers parameters were taken: +# https://github.com/Ensembl/ensembl-rest/wiki/HTTP-Headers + +request_headers <- + function(accept = NULL, + accept_encoding = NULL, + content_type = "application/json", + origin = NULL) { + .headers <- list( + accept = accept, + accept_encoding = accept_encoding, + content_type = content_type, + origin = origin + ) + + .headers <- + .headers[!sapply(.headers, is.null)] # this will remove NULL entries + + structure(.headers, class = "request_headers") + } + +response_headers <- + function(access_control_allow_origin = "*", + content_length = NULL, + content_type = "text/x-fasta", + retry_after = NULL, + x_runtime = NULL, + x_rate_limit_limit = NULL, + x_rate_limit_reset = NULL, + x_rate_limit_period = NULL, + x_rate_limit_remaining = NULL) { + + ..headers <- list( + access_control_allow_origin = access_control_allow_origin, + content_length = content_length, + content_type = content_type, + retry_after = retry_after, + x_runtime = x_runtime, + x_rate_limit_limit = x_rate_limit_limit, + x_rate_limit_reset = x_rate_limit_reset, + x_rate_limit_period = x_rate_limit_period, + x_rate_limit_remaining = x_rate_limit_remaining + ) + + ..headers <- + ..headers[!sapply(..headers, is.null)] + + structure(..headers, class = "response_headers") + } + + +base_url <- function() "https://rest.ensembl.org" + +user_agent <- function() "ensemblr (https://www.pattern.institute/ensemblr)" + +# Example: +# +# req("/cafe/genetree/member/symbol/{species}/{symbol}", species = "homo_sapiens", symbol = "BRCA2") |> +# httr2::req_perform() |> +# httr2::resp_body_json() +req <- + function(res, + ..., + .body = NULL, + .headers = request_headers()) { + + # All parameters. + params <- list(...) + pnames <- names(params) + + # Required parameters. + req_pnames <- vars_in_braces(res) + req_params <- params[req_pnames] + + # Optional parameters. + opt_pnames <- setdiff(pnames, req_pnames) + opt_params <- params[opt_pnames] + + res <- glue::glue(res, .envir = as.environment(req_params)) + + req <- + httr2::request(base_url()) |> + httr2::req_url_path_append(res) |> + httr2::req_url_query(!!!opt_params) |> + httr2::req_headers( + Accept = .headers$accept, + `Accept-Encoding` = .headers$accept_encoding, + `Content-Type` = .headers$content_type, + Origin = .headers$origin + ) |> + httr2::req_user_agent(user_agent()) + + if (!is.null(.body)) { + req <- httr2::req_body_raw(req, body = .body, type = .headers$content_type) + } + + req + } + +reqs <- function(res, + ..., + .body = NULL, + .headers = request_headers()) { + params <- list(...) + .body <- .body %||% list(.body) + + req_args <- + vctrs::vec_recycle_common( + res = res, + !!!params, + .body = .body, + .type = .headers$content_type + ) + reqs <- purrr::pmap(.l = req_args, .f = req) + + reqs +} From 8eb4f53d38d0fbf5883f0358ee88d9c7bc96ce1f Mon Sep 17 00:00:00 2001 From: danymukesha Date: Thu, 5 Sep 2024 15:29:44 +0200 Subject: [PATCH 08/28] integrate helper functions in req --- R/req.R | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/R/req.R b/R/req.R index 5bae582..7414bc2 100755 --- a/R/req.R +++ b/R/req.R @@ -5,14 +5,14 @@ vars_in_braces <- function(x) { vars } -# Helper functions for http headers +# Helper functions for http headers (should we keep them in this file?) # The reference to which headers parameters were taken: # https://github.com/Ensembl/ensembl-rest/wiki/HTTP-Headers request_headers <- function(accept = NULL, accept_encoding = NULL, - content_type = "application/json", + content_type = "application/json", # as default origin = NULL) { .headers <- list( accept = accept, @@ -30,7 +30,7 @@ request_headers <- response_headers <- function(access_control_allow_origin = "*", content_length = NULL, - content_type = "text/x-fasta", + content_type = "application/json", retry_after = NULL, x_runtime = NULL, x_rate_limit_limit = NULL, @@ -101,6 +101,8 @@ req <- if (!is.null(.body)) { req <- httr2::req_body_raw(req, body = .body, type = .headers$content_type) } + #add `query_params` object, to give the user the possibility which one they used + req$query_params <- opt_params req } From ccf2b52236606b926f88aa7b56a4c114cfc46905 Mon Sep 17 00:00:00 2001 From: danymukesha Date: Thu, 5 Sep 2024 15:33:04 +0200 Subject: [PATCH 09/28] rename user agent unit test and updated function from user_agent_id to user_agent --- tests/testthat/test-user-agent-id.R | 4 ---- tests/testthat/test-user-agent.R | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 tests/testthat/test-user-agent-id.R create mode 100755 tests/testthat/test-user-agent.R diff --git a/tests/testthat/test-user-agent-id.R b/tests/testthat/test-user-agent-id.R deleted file mode 100644 index 4a1f764..0000000 --- a/tests/testthat/test-user-agent-id.R +++ /dev/null @@ -1,4 +0,0 @@ -test_that("user_agent_id() works", { - user_agent_desc <- "ensemblr (https://www.pattern.institute/ensemblr)" - expect_equal(user_agent_id(), user_agent_desc) -}) diff --git a/tests/testthat/test-user-agent.R b/tests/testthat/test-user-agent.R new file mode 100755 index 0000000..48a3410 --- /dev/null +++ b/tests/testthat/test-user-agent.R @@ -0,0 +1,4 @@ +test_that("user_agent() works", { + user_agent_desc <- "ensemblr (https://www.pattern.institute/ensemblr)" + expect_equal(user_agent(), user_agent_desc) +}) From 19fd463ddf3addb6d58667c0cdcf9afa0e3affe0 Mon Sep 17 00:00:00 2001 From: danymukesha Date: Thu, 5 Sep 2024 15:49:40 +0200 Subject: [PATCH 10/28] add tests for req, http-headers, base-ulr functions --- tests/testthat/test-base-url.R | 4 ++ tests/testthat/test-http-headers.R | 18 ++++++ tests/testthat/test-req.R | 92 ++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100755 tests/testthat/test-base-url.R create mode 100755 tests/testthat/test-http-headers.R create mode 100755 tests/testthat/test-req.R diff --git a/tests/testthat/test-base-url.R b/tests/testthat/test-base-url.R new file mode 100755 index 0000000..942ae02 --- /dev/null +++ b/tests/testthat/test-base-url.R @@ -0,0 +1,4 @@ +test_that("base_url() returns correct URL", { + ensembl_url <- "https://rest.ensembl.org" + expect_equal(base_url(), ensembl_url) +}) diff --git a/tests/testthat/test-http-headers.R b/tests/testthat/test-http-headers.R new file mode 100755 index 0000000..4e025d3 --- /dev/null +++ b/tests/testthat/test-http-headers.R @@ -0,0 +1,18 @@ +test_that("request_headers creates correct structure", { + headers <- request_headers(accept = "application/json", content_type = "text/plain") + expect_s3_class(headers, "request_headers") + expect_named(headers, c("accept", "content_type")) + expect_equal(headers$accept, "application/json") + expect_equal(headers$content_type, "text/plain") + expect_null(headers$no_existing_param) + # (if someone passes a number instead of a string, for instance) + expect_false(is.character(request_headers(accept = 123)$accept), "is.character") +}) + +test_that("response_headers creates correct structure", { + headers <- response_headers(content_type = "application/json", x_runtime = "0.01") + expect_s3_class(headers, "response_headers") + expect_named(headers, c("access_control_allow_origin", "content_type", "x_runtime")) + expect_equal(headers$content_type, "application/json") + expect_equal(headers$x_runtime, "0.01") +}) diff --git a/tests/testthat/test-req.R b/tests/testthat/test-req.R new file mode 100755 index 0000000..8ca547d --- /dev/null +++ b/tests/testthat/test-req.R @@ -0,0 +1,92 @@ +# start with basic function +test_that("vars_in_braces extracts variables correctly", { + expect_equal(vars_in_braces("Hello {world}"), "world") + expect_equal(vars_in_braces("/{species}/{symbol}"), c("species", "symbol")) + expect_equal(vars_in_braces("No braces here"), character(0)) + expect_equal(vars_in_braces("{a} {b} {c}"), c("a", "b", "c")) +}) + +testthat::skip_on_cran() # the next tests depends on ensembl database, +#hence these tests will be skipped for cran, to avoid +#that in the case the ensembl database is down the test have to go through + +testthat::skip_if_offline() # if you are offline + +test_that("req function builds correct request", { + test_req <- req("/cafe/genetree/member/symbol/{species}/{symbol}", + species = "homo_sapiens", + symbol = "BRCA2", + version = NULL, + .headers = request_headers(accept = "application/json")) + + expect_equal(test_req$url, paste0(base_url(), "/cafe/genetree/member/symbol/homo_sapiens/BRCA2")) + expect_equal(test_req$headers$Accept, "application/json") + expect_equal(test_req$headers$`Accept-Encoding`, NULL) + expect_equal(test_req$headers$`Content-Type`, "application/json") + expect_equal(test_req$headers$Origin, NULL) + expect_equal(test_req$options$useragent, user_agent()) +}) + +#test that the function raises an error when required parameters are missing +test_that("req function raises error for missing required parameters", { + expect_error( + req("/cafe/genetree/member/symbol/{species}/{symbol}", + species = "homo_sapiens"), + "object 'symbol' not found" + ) + expect_error( + req("/cafe/genetree/member/symbol/{species}/{symbol}", symbol = "BRCA2"), + "object 'species' not found" + ) +}) + +test_that("req function sets body if provided", { + test_req <- req("/cafe/genetree/member/symbol/{species}/{symbol}", + species = "homo_sapiens", + symbol = "BRCA2", + .body = "test body content", + .headers = request_headers(content_type = "text/plain")) + expect_equal(charToRaw(test_req$body$data), charToRaw("test body content")) + expect_equal(test_req$headers$`Content-Type`, "text/plain") +}) + +# tests for optional parameters only +test_that("req function handles optional parameters correctly", { + test_req <- req("/path/to/resource", + optional_param1 = "value1", + optional_param2 = "value2") + expect_equal(test_req$query_params, list(optional_param1 = "value1", + optional_param2 = "value2")) + expect_equal(test_req$url, paste0(base_url(), "/path/to/resource", + "?optional_param1=", "value1", + "&optional_param2=", "value2")) +}) + +test_that("req function does not set body when .body is NULL", { + test_req <- req("/cafe/genetree/member/symbol/{species}/{symbol}", + species = "homo_sapiens", + symbol = "BRCA2", + .headers = request_headers(content_type = "application/json")) + expect_null(test_req$body) +}) + +# test for invalid or `NULL` header inputs +test_that("req function handles invalid headers", { + test_req <- req("/path/to/resource", .headers = request_headers()) + expect_false(any(is.null(test_req$headers))) +}) + +# Test for edge cases with special characters in parameters +test_that("req function correctly handles special characters in parameters", { + test_req <- req("/path", query_param = "special?chars&") + expect_equal(test_req$query_params, list(query_param = "special?chars&")) +}) + +# in case of missing http headers argument (using defaults); +# content type defaults to application/json when not provided +test_that("req function handles default headers", { + test_req <- req("/path/to/resource") + expect_equal(test_req$headers$`Content-Type`, "application/json") + expect_equal(test_req$headers$Accept, NULL) + expect_equal(test_req$headers$Origin, NULL) +}) From e0de7d610ebe01fc8d328b3999c02cd005c69a77 Mon Sep 17 00:00:00 2001 From: danymukesha Date: Thu, 5 Sep 2024 16:38:57 +0200 Subject: [PATCH 11/28] add testthat among the imports on DESCRIPTION --- DESCRIPTION | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) mode change 100644 => 100755 DESCRIPTION diff --git a/DESCRIPTION b/DESCRIPTION old mode 100644 new mode 100755 index 9efe068..c746471 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -49,7 +49,8 @@ Imports: memoise, httr2, tidyjson, - tibblify + tibblify, + testthat Suggests: knitr, rmarkdown From b9bd4c2fa7029738adc11c059ced26223da3f847 Mon Sep 17 00:00:00 2001 From: danymukesha Date: Thu, 5 Sep 2024 20:53:32 +0200 Subject: [PATCH 12/28] add some more tests --- tests/testthat/test-req.R | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-req.R b/tests/testthat/test-req.R index 8ca547d..04b424c 100755 --- a/tests/testthat/test-req.R +++ b/tests/testthat/test-req.R @@ -70,13 +70,11 @@ test_that("req function does not set body when .body is NULL", { expect_null(test_req$body) }) -# test for invalid or `NULL` header inputs -test_that("req function handles invalid headers", { +test_that("req function handles invalid or null headers", { test_req <- req("/path/to/resource", .headers = request_headers()) expect_false(any(is.null(test_req$headers))) }) -# Test for edge cases with special characters in parameters test_that("req function correctly handles special characters in parameters", { test_req <- req("/path", query_param = "special?chars&") expect_equal(test_req$query_params, list(query_param = "special?chars&")) @@ -90,3 +88,32 @@ test_that("req function handles default headers", { expect_equal(test_req$headers$Accept, NULL) expect_equal(test_req$headers$Origin, NULL) }) + + +# ------------- GET Request Tests ------------- + +test_that("GET req sends a valid GET request with valid id", { + res <- req("/archive/id/{id}", id = "ENSG00000157764") |> + httr2::req_perform() + + expect_s3_class(res, "httr2_response") + expect_equal(res$url, "https://rest.ensembl.org/archive/id/ENSG00000157764") + expect_equal(res$method, "GET") + expect_true("Content-Type" %in% names(res$headers)) + expect_equal(res$headers$`Content-Type`, "application/json") +}) + +test_that("GET req sends correct callback parameter in URL", { + res <- req("/archive/id/{id}", id = "ENSG00000157764", callback = "randomlygeneratedname") + expect_equal(res$query_params$callback, "randomlygeneratedname") + expect_match(res$url, "callback=randomlygeneratedname") +}) + +test_that("GET req sets correct headers", { + res <- req("/archive/id/{id}", id = "ENSG00000157764") + expect_equal(res$headers$`Content-Type`, "application/json") +}) + +# ------------- POST Request Tests ------------- + +## to be done From 87c82dad7e65d55ff1103749d7415a0584e35cc8 Mon Sep 17 00:00:00 2001 From: Ramiro Magno Date: Sun, 8 Sep 2024 16:35:57 +0100 Subject: [PATCH 13/28] Refactoring `req()` / `req_headers()` --- DESCRIPTION | 1 + R/http-headers.R | 60 +++++++ R/req.R | 201 ++++++++-------------- R/vars-in-braces.R | 6 + man/get_analyses.Rd | 16 +- man/get_id.Rd | 22 +-- man/get_ld_variants_by_window.Rd | 20 +-- man/get_species.Rd | 40 ++--- man/get_versioning.Rd | 2 +- man/is_ensembl_reachable.Rd | 2 +- man/pairwise_combn.Rd | 2 +- man/req.Rd | 27 +++ man/warn_when_request_errored.Rd | 4 +- tests/testthat/test-http-headers.R | 54 ++++-- tests/testthat/test-req.R | 241 ++++++++++++++------------- tests/testthat/test-vars-in-braces.R | 7 + 16 files changed, 387 insertions(+), 318 deletions(-) create mode 100644 R/http-headers.R create mode 100644 R/vars-in-braces.R create mode 100644 man/req.Rd create mode 100644 tests/testthat/test-vars-in-braces.R diff --git a/DESCRIPTION b/DESCRIPTION index c746471..ceae92c 100755 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -58,3 +58,4 @@ VignetteBuilder: knitr URL: https://github.com/patterninstitute/ensemblr, https://www.pattern.institute/ensemblr/ BugReports: https://github.com/patterninstitute/ensemblr/issues Config/Needs/website: patterninstitute/chic +Roxygen: list(markdown = TRUE) diff --git a/R/http-headers.R b/R/http-headers.R new file mode 100644 index 0000000..0624dca --- /dev/null +++ b/R/http-headers.R @@ -0,0 +1,60 @@ +req_header_names <- function() { + c("Accept", "Accept-Encoding", "Content-Type", "Origin") +} + +res_header_names <- function() { + c( + "Access-Control-Allow-Origin", + "Content-Length", + "Content-Type", + "Retry-After", + "X-Runtime", + "X-RateLimit-Limit", + "X-RateLimit-Reset", + "X-RateLimit-Period", + "X-RateLimit-Remaining" + ) +} + +req_headers <- + function(accept = NULL, + accept_encoding = NULL, + content_type = "application/json", # as default + origin = NULL) { + + headers_lst <- + list( + Accept = accept, + `Accept-Encoding` = accept_encoding, + `Content-Type` = content_type, + Origin = origin + ) + + structure(headers_lst, class = "ensemblr_req_hdr") + } + +res_headers <- + function(access_control_allow_origin = "*", + content_length = NULL, + content_type = "application/json", + retry_after = NULL, + x_runtime = NULL, + x_rate_limit_limit = NULL, + x_rate_limit_reset = NULL, + x_rate_limit_period = NULL, + x_rate_limit_remaining = NULL) { + + headers_lst <- list( + `Access-Control-Allow-Origin` = access_control_allow_origin, + `Content-Length` = content_length, + `Content-Type` = content_type, + `Retry-After` = retry_after, + `X-Runtime` = x_runtime, + `X-RateLimit-Limit` = x_rate_limit_limit, + `X-RateLimit-Reset` = x_rate_limit_reset, + `X-RateLimit-Period` = x_rate_limit_period, + `X-RateLimit-Remaining` = x_rate_limit_remaining + ) + + structure(headers_lst, class = "ensemblr_res_hdr") + } diff --git a/R/req.R b/R/req.R index 7414bc2..9b9572e 100755 --- a/R/req.R +++ b/R/req.R @@ -1,127 +1,74 @@ -vars_in_braces <- function(x) { - matches <- stringr::str_extract_all(x, "\\{([^}]+)\\}") - vars <- gsub("[{}]", "", unlist(matches)) - - vars -} - -# Helper functions for http headers (should we keep them in this file?) -# The reference to which headers parameters were taken: -# https://github.com/Ensembl/ensembl-rest/wiki/HTTP-Headers - -request_headers <- - function(accept = NULL, - accept_encoding = NULL, - content_type = "application/json", # as default - origin = NULL) { - .headers <- list( - accept = accept, - accept_encoding = accept_encoding, - content_type = content_type, - origin = origin - ) - - .headers <- - .headers[!sapply(.headers, is.null)] # this will remove NULL entries - - structure(.headers, class = "request_headers") - } - -response_headers <- - function(access_control_allow_origin = "*", - content_length = NULL, - content_type = "application/json", - retry_after = NULL, - x_runtime = NULL, - x_rate_limit_limit = NULL, - x_rate_limit_reset = NULL, - x_rate_limit_period = NULL, - x_rate_limit_remaining = NULL) { - - ..headers <- list( - access_control_allow_origin = access_control_allow_origin, - content_length = content_length, - content_type = content_type, - retry_after = retry_after, - x_runtime = x_runtime, - x_rate_limit_limit = x_rate_limit_limit, - x_rate_limit_reset = x_rate_limit_reset, - x_rate_limit_period = x_rate_limit_period, - x_rate_limit_remaining = x_rate_limit_remaining - ) - - ..headers <- - ..headers[!sapply(..headers, is.null)] - - structure(..headers, class = "response_headers") - } - - -base_url <- function() "https://rest.ensembl.org" - -user_agent <- function() "ensemblr (https://www.pattern.institute/ensemblr)" - -# Example: -# -# req("/cafe/genetree/member/symbol/{species}/{symbol}", species = "homo_sapiens", symbol = "BRCA2") |> -# httr2::req_perform() |> -# httr2::resp_body_json() -req <- - function(res, - ..., - .body = NULL, - .headers = request_headers()) { - - # All parameters. - params <- list(...) - pnames <- names(params) - - # Required parameters. - req_pnames <- vars_in_braces(res) - req_params <- params[req_pnames] - - # Optional parameters. - opt_pnames <- setdiff(pnames, req_pnames) - opt_params <- params[opt_pnames] - - res <- glue::glue(res, .envir = as.environment(req_params)) - - req <- - httr2::request(base_url()) |> - httr2::req_url_path_append(res) |> - httr2::req_url_query(!!!opt_params) |> - httr2::req_headers( - Accept = .headers$accept, - `Accept-Encoding` = .headers$accept_encoding, - `Content-Type` = .headers$content_type, - Origin = .headers$origin - ) |> - httr2::req_user_agent(user_agent()) - - if (!is.null(.body)) { - req <- httr2::req_body_raw(req, body = .body, type = .headers$content_type) - } - #add `query_params` object, to give the user the possibility which one they used - req$query_params <- opt_params - - req - } - -reqs <- function(res, - ..., - .body = NULL, - .headers = request_headers()) { - params <- list(...) - .body <- .body %||% list(.body) - - req_args <- - vctrs::vec_recycle_common( - res = res, - !!!params, - .body = .body, - .type = .headers$content_type - ) - reqs <- purrr::pmap(.l = req_args, .f = req) - - reqs -} +base_url <- function() "https://rest.ensembl.org" + +user_agent <- function() "ensemblr (https://www.pattern.institute/ensemblr)" + +#' Create a new HTTP request +#' +#' [req()] creates an HTTP request object. +#' +#' @param res A resource (res) URL as a string. This string supports embedding +#' of R variable names in curly braces whose values are looked up in parameter +#' names supplied in `...` and interpolated. +#' +#' @param ... Name value pairs specifying query components or parameters. +#' +#' @param .body A literal string or raw vector to send as body. +#' +#' @param .headers An S3 list with class `ensemblr_req_hdr`. Use the helper +#' [req_headers()] to create such an object. +#' +#' @inherit httr2::request return +#' +#' @keywords internal +req <- + function(res, + ..., + .body = NULL, + .headers = req_headers()) { + + # All parameters. + params <- list(...) + pnames <- names(params) + + # Required parameters. + req_pnames <- vars_in_braces(res) + req_params <- params[req_pnames] + + # Optional parameters. + opt_pnames <- setdiff(pnames, req_pnames) + opt_params <- params[opt_pnames] + + res <- glue::glue(res, .envir = as.environment(req_params)) + + req <- + httr2::request(base_url()) |> + httr2::req_url_path_append(res) |> + httr2::req_url_query(!!!opt_params) |> + httr2::req_headers(!!!.headers) |> + httr2::req_user_agent(user_agent()) + + if (!is.null(.body)) { + req <- httr2::req_body_raw(req, body = .body, type = .headers$content_type) + } + + req + } + +reqs <- function(res, + ..., + .body = NULL, + .headers = req_headers()) { + params <- list(...) + .body <- .body %||% list(.body) + + req_args <- + vctrs::vec_recycle_common( + res = res, + !!!params, + .body = .body, + .type = .headers$content_type + ) + reqs <- purrr::pmap(.l = req_args, .f = req) + + reqs +} diff --git a/R/vars-in-braces.R b/R/vars-in-braces.R new file mode 100644 index 0000000..c9e0be3 --- /dev/null +++ b/R/vars-in-braces.R @@ -0,0 +1,6 @@ +vars_in_braces <- function(x) { + matches <- stringr::str_extract_all(x, "\\{([^}]+)\\}") + vars <- gsub("[{}]", "", unlist(matches)) + + vars +} diff --git a/man/get_analyses.Rd b/man/get_analyses.Rd index 27682b9..2b2f962 100644 --- a/man/get_analyses.Rd +++ b/man/get_analyses.Rd @@ -26,14 +26,14 @@ responses' status.} \value{ A \code{\link[tibble]{tibble}} of 3 variables: \describe{ - \item{\code{species_name}}{Ensembl species name: this is the name used - internally by Ensembl to uniquely identify a species by name. It is the - scientific name but formatted without capitalisation and spacing converted - with an underscore, e.g., \code{'homo_sapiens'}.} - \item{\code{database}}{Ensembl database. Typically one of \code{'core'}, - \code{'rnaseq'}, \code{'cdna'}, \code{'funcgen'} and - \code{'otherfeatures'}.} - \item{\code{analysis}}{Analysis.} +\item{\code{species_name}}{Ensembl species name: this is the name used +internally by Ensembl to uniquely identify a species by name. It is the +scientific name but formatted without capitalisation and spacing converted +with an underscore, e.g., \code{'homo_sapiens'}.} +\item{\code{database}}{Ensembl database. Typically one of \code{'core'}, +\code{'rnaseq'}, \code{'cdna'}, \code{'funcgen'} and +\code{'otherfeatures'}.} +\item{\code{analysis}}{Analysis.} } } \description{ diff --git a/man/get_id.Rd b/man/get_id.Rd index 4829b89..9b256d8 100644 --- a/man/get_id.Rd +++ b/man/get_id.Rd @@ -23,17 +23,17 @@ responses' status.} \value{ A \code{\link[tibble]{tibble}} of 9 variables: \describe{ - \item{\code{id}}{Ensembl identifier.} - \item{\code{id_latest}}{Ensembl identifier including the version suffix.} - \item{\code{type}}{Entity type: gene (\code{'Gene'}), exon (\code{'Exon'}), - transcript (\code{'Transcript'}), and protein (\code{'Translation'}).} - \item{\code{id_version}}{Ensembl identifier version, indicates how many - times that entity has changed during its time in Ensembl.} - \item{\code{release}}{Ensembl release version.} - \item{\code{is_current}}{Is this the latest identifier for the represented entity.} - \item{\code{genome_assembly_name}}{Code name of the genome assembly.} - \item{\code{peptide}}{TODO} - \item{\code{possible_replacement}}{TODO} +\item{\code{id}}{Ensembl identifier.} +\item{\code{id_latest}}{Ensembl identifier including the version suffix.} +\item{\code{type}}{Entity type: gene (\code{'Gene'}), exon (\code{'Exon'}), +transcript (\code{'Transcript'}), and protein (\code{'Translation'}).} +\item{\code{id_version}}{Ensembl identifier version, indicates how many +times that entity has changed during its time in Ensembl.} +\item{\code{release}}{Ensembl release version.} +\item{\code{is_current}}{Is this the latest identifier for the represented entity.} +\item{\code{genome_assembly_name}}{Code name of the genome assembly.} +\item{\code{peptide}}{TODO} +\item{\code{possible_replacement}}{TODO} } } \description{ diff --git a/man/get_ld_variants_by_window.Rd b/man/get_ld_variants_by_window.Rd index 2d53f63..4b3c7c6 100644 --- a/man/get_ld_variants_by_window.Rd +++ b/man/get_ld_variants_by_window.Rd @@ -87,7 +87,7 @@ populations for a species.} \item{r_squared}{\eqn{r^2} is a measure of linkage disequilibrium. \code{r_squared} defines a cut-off threshold: only variants whose \eqn{r^2 -\ge }\code{r_squared} are returned. The lower bound for \code{r_squared} is + \ge }\code{r_squared} are returned. The lower bound for \code{r_squared} is \code{0.05}, not \code{0}; the upper bound is \code{1}.} \item{verbose}{Whether to be verbose about the http requests and respective @@ -116,15 +116,15 @@ function \code{get_ld_variants_by_range()}.} \value{ A \code{\link[tibble]{tibble}} of 6 variables: \describe{ - \item{\code{species_name}}{Ensembl species name: this is the name used internally - by Ensembl to uniquely identify a species by name. It is the scientific - name but formatted without capitalisation and spacing converted with an - underscore, e.g., \code{'homo_sapiens'}.} - \item{\code{population}}{Population for which to compute linkage disequilibrium.} - \item{\code{variant_id1}}{First variant identifier.} - \item{\code{variant_id2}}{Second variant identifier.} - \item{\code{d_prime}}{\eqn{D'} between the two variants.} - \item{\code{r_squared}}{\eqn{r^2} between the two variants.} +\item{\code{species_name}}{Ensembl species name: this is the name used internally +by Ensembl to uniquely identify a species by name. It is the scientific +name but formatted without capitalisation and spacing converted with an +underscore, e.g., \code{'homo_sapiens'}.} +\item{\code{population}}{Population for which to compute linkage disequilibrium.} +\item{\code{variant_id1}}{First variant identifier.} +\item{\code{variant_id2}}{Second variant identifier.} +\item{\code{d_prime}}{\eqn{D'} between the two variants.} +\item{\code{r_squared}}{\eqn{r^2} between the two variants.} } } \description{ diff --git a/man/get_species.Rd b/man/get_species.Rd index ca33859..c0fde1a 100644 --- a/man/get_species.Rd +++ b/man/get_species.Rd @@ -27,26 +27,26 @@ responses' status.} \value{ A \code{\link[tibble]{tibble}} of 12 variables: \describe{ - \item{division}{Ensembl division: \code{"EnsemblVertebrates"}, - \code{"EnsemblMetazoa"}, \code{"EnsemblPlants"}, \code{"EnsemblProtists"}, - \code{"EnsemblFungi"} or \code{"EnsemblBacteria"}.} - \item{taxon_id}{NCBI taxon identifier.} - \item{species_name}{Ensembl species name: this is the name used internally - by Ensembl to uniquely identify a species by name. It is the scientific - name but formatted without capitalisation and spacing converted with an - underscore, e.g., \code{'homo_sapiens'}.} - \item{species_display_name}{Species display name: the name used for display - on Ensembl website.} - \item{species_common_name}{Species common name.} - \item{release}{Ensembl release version.} - \item{genome_assembly_name}{Code name of the genome assembly.} - \item{genbank_assembly_accession}{Genbank assembly accession identifier.} - \item{strain}{Species strain.} - \item{strain_collection}{Species strain collection.} - \item{species_aliases}{Other names or acronyms used to refer to the - species. Note that this column is of the list type.} - \item{groups}{Ensembl databases for which data exists for this species. - Note that this column is of the list type.} +\item{division}{Ensembl division: \code{"EnsemblVertebrates"}, +\code{"EnsemblMetazoa"}, \code{"EnsemblPlants"}, \code{"EnsemblProtists"}, +\code{"EnsemblFungi"} or \code{"EnsemblBacteria"}.} +\item{taxon_id}{NCBI taxon identifier.} +\item{species_name}{Ensembl species name: this is the name used internally +by Ensembl to uniquely identify a species by name. It is the scientific +name but formatted without capitalisation and spacing converted with an +underscore, e.g., \code{'homo_sapiens'}.} +\item{species_display_name}{Species display name: the name used for display +on Ensembl website.} +\item{species_common_name}{Species common name.} +\item{release}{Ensembl release version.} +\item{genome_assembly_name}{Code name of the genome assembly.} +\item{genbank_assembly_accession}{Genbank assembly accession identifier.} +\item{strain}{Species strain.} +\item{strain_collection}{Species strain collection.} +\item{species_aliases}{Other names or acronyms used to refer to the +species. Note that this column is of the list type.} +\item{groups}{Ensembl databases for which data exists for this species. +Note that this column is of the list type.} } } \description{ diff --git a/man/get_versioning.Rd b/man/get_versioning.Rd index 5907d21..e9ef3ff 100644 --- a/man/get_versioning.Rd +++ b/man/get_versioning.Rd @@ -13,7 +13,7 @@ get_versioning(verbose = FALSE, warnings = TRUE) } \value{ A named list of three elements: \code{data}, \code{software} and - \code{rest}. +\code{rest}. } \description{ This function gets the versions of the different entities involved in the diff --git a/man/is_ensembl_reachable.Rd b/man/is_ensembl_reachable.Rd index b919d9c..3b072a7 100644 --- a/man/is_ensembl_reachable.Rd +++ b/man/is_ensembl_reachable.Rd @@ -17,7 +17,7 @@ change this parameter.} } \value{ A logical value: \code{TRUE} if EBI server is reachable, \code{FALSE} - otherwise. +otherwise. } \description{ Check if the Ensembl server where REST API service is running is reachable. diff --git a/man/pairwise_combn.Rd b/man/pairwise_combn.Rd index 003bf3e..b2d15a1 100644 --- a/man/pairwise_combn.Rd +++ b/man/pairwise_combn.Rd @@ -11,7 +11,7 @@ pairwise_combn(x) } \value{ A \code{\link[tibble]{tibble}} of two columns where each row is a - pairwise combination. +pairwise combination. } \description{ Generates pairwise combinations from the supplied vector. Never returns the diff --git a/man/req.Rd b/man/req.Rd new file mode 100644 index 0000000..e322420 --- /dev/null +++ b/man/req.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/req.R +\name{req} +\alias{req} +\title{Create a new HTTP request} +\usage{ +req(res, ..., .body = NULL, .headers = req_headers()) +} +\arguments{ +\item{res}{A resource (res) URL as a string. This string supports embedding +of R variable names in curly braces whose values are looked up in parameter +names supplied in \code{...} and interpolated.} + +\item{...}{Name value pairs specifying query components or parameters.} + +\item{.body}{A literal string or raw vector to send as body.} + +\item{.headers}{An S3 list with class \code{ensemblr_req_hdr}. Use the helper +\code{\link[=req_headers]{req_headers()}} to create such an object.} +} +\value{ +An HTTP request: an S3 list with class \code{httr2_request}. +} +\description{ +\code{\link[=req]{req()}} creates an HTTP request object. +} +\keyword{internal} diff --git a/man/warn_when_request_errored.Rd b/man/warn_when_request_errored.Rd index 8980d65..a3af60e 100644 --- a/man/warn_when_request_errored.Rd +++ b/man/warn_when_request_errored.Rd @@ -11,8 +11,8 @@ warn_when_request_errored(response) } \value{ A scalar character vector with a warning message, or the string - \code{'OK'} if the response was successful, although this function is - called mostly for its side effect, i.e., the triggering of a warning. +\code{'OK'} if the response was successful, although this function is +called mostly for its side effect, i.e., the triggering of a warning. } \description{ Warn if an httr \code{\link[httr]{response}} errored. It also returns a tidy diff --git a/tests/testthat/test-http-headers.R b/tests/testthat/test-http-headers.R index 4e025d3..614a19a 100755 --- a/tests/testthat/test-http-headers.R +++ b/tests/testthat/test-http-headers.R @@ -1,18 +1,36 @@ -test_that("request_headers creates correct structure", { - headers <- request_headers(accept = "application/json", content_type = "text/plain") - expect_s3_class(headers, "request_headers") - expect_named(headers, c("accept", "content_type")) - expect_equal(headers$accept, "application/json") - expect_equal(headers$content_type, "text/plain") - expect_null(headers$no_existing_param) - # (if someone passes a number instead of a string, for instance) - expect_false(is.character(request_headers(accept = 123)$accept), "is.character") -}) - -test_that("response_headers creates correct structure", { - headers <- response_headers(content_type = "application/json", x_runtime = "0.01") - expect_s3_class(headers, "response_headers") - expect_named(headers, c("access_control_allow_origin", "content_type", "x_runtime")) - expect_equal(headers$content_type, "application/json") - expect_equal(headers$x_runtime, "0.01") -}) +test_that("req_headers creates correct structure", { + headers <- req_headers(accept = "application/json", content_type = "text/plain") + + # Check object class + expect_s3_class(headers, "ensemblr_req_hdr") + + # Check that list names match the expect header names. + expect_setequal(names(headers), req_header_names()) + + # Check that only only defined headers are different from `NULL`. + expect_named(headers[!sapply(headers, is.null)], c("Accept", "Content-Type")) + + # Check that defined headers have the assigned values. + expect_equal(headers$Accept, "application/json") + expect_equal(headers$`Content-Type`, "text/plain") +}) + +# test_that("res_headers creates correct structure", { +# headers <- response_headers(content_type = "application/json", x_runtime = "0.01") +# +# # Check that list names match the expect header names. +# expect_setequal(names(headers), res_header_names()) +# +# # Check that only only defined headers are different from `NULL`. +# expect_named(headers[!sapply(headers, is.null)], c("Accept", "Content-Type")) +# +# # Check that defined headers have the assigned values. +# expect_equal(headers$Accept, "application/json") +# expect_equal(headers$`Content-Type`, "text/plain") +# +# +# expect_s3_class(headers, "ensemblr_res_hdr") +# expect_named(headers, c("access_control_allow_origin", "content_type", "x_runtime")) +# expect_equal(headers$content_type, "application/json") +# expect_equal(headers$x_runtime, "0.01") +# }) diff --git a/tests/testthat/test-req.R b/tests/testthat/test-req.R index 04b424c..892a173 100755 --- a/tests/testthat/test-req.R +++ b/tests/testthat/test-req.R @@ -1,119 +1,122 @@ -# start with basic function -test_that("vars_in_braces extracts variables correctly", { - expect_equal(vars_in_braces("Hello {world}"), "world") - expect_equal(vars_in_braces("/{species}/{symbol}"), c("species", "symbol")) - expect_equal(vars_in_braces("No braces here"), character(0)) - expect_equal(vars_in_braces("{a} {b} {c}"), c("a", "b", "c")) -}) - -testthat::skip_on_cran() # the next tests depends on ensembl database, -#hence these tests will be skipped for cran, to avoid -#that in the case the ensembl database is down the test have to go through - -testthat::skip_if_offline() # if you are offline - -test_that("req function builds correct request", { - test_req <- req("/cafe/genetree/member/symbol/{species}/{symbol}", - species = "homo_sapiens", - symbol = "BRCA2", - version = NULL, - .headers = request_headers(accept = "application/json")) - - expect_equal(test_req$url, paste0(base_url(), "/cafe/genetree/member/symbol/homo_sapiens/BRCA2")) - expect_equal(test_req$headers$Accept, "application/json") - expect_equal(test_req$headers$`Accept-Encoding`, NULL) - expect_equal(test_req$headers$`Content-Type`, "application/json") - expect_equal(test_req$headers$Origin, NULL) - expect_equal(test_req$options$useragent, user_agent()) -}) - -#test that the function raises an error when required parameters are missing -test_that("req function raises error for missing required parameters", { - expect_error( - req("/cafe/genetree/member/symbol/{species}/{symbol}", - species = "homo_sapiens"), - "object 'symbol' not found" - ) - expect_error( - req("/cafe/genetree/member/symbol/{species}/{symbol}", symbol = "BRCA2"), - "object 'species' not found" - ) -}) - -test_that("req function sets body if provided", { - test_req <- req("/cafe/genetree/member/symbol/{species}/{symbol}", - species = "homo_sapiens", - symbol = "BRCA2", - .body = "test body content", - .headers = request_headers(content_type = "text/plain")) - expect_equal(charToRaw(test_req$body$data), charToRaw("test body content")) - expect_equal(test_req$headers$`Content-Type`, "text/plain") -}) - -# tests for optional parameters only -test_that("req function handles optional parameters correctly", { - test_req <- req("/path/to/resource", - optional_param1 = "value1", - optional_param2 = "value2") - expect_equal(test_req$query_params, list(optional_param1 = "value1", - optional_param2 = "value2")) - expect_equal(test_req$url, paste0(base_url(), "/path/to/resource", - "?optional_param1=", "value1", - "&optional_param2=", "value2")) -}) - -test_that("req function does not set body when .body is NULL", { - test_req <- req("/cafe/genetree/member/symbol/{species}/{symbol}", - species = "homo_sapiens", - symbol = "BRCA2", - .headers = request_headers(content_type = "application/json")) - expect_null(test_req$body) -}) - -test_that("req function handles invalid or null headers", { - test_req <- req("/path/to/resource", .headers = request_headers()) - expect_false(any(is.null(test_req$headers))) -}) - -test_that("req function correctly handles special characters in parameters", { - test_req <- req("/path", query_param = "special?chars&") - expect_equal(test_req$query_params, list(query_param = "special?chars&")) -}) - -# in case of missing http headers argument (using defaults); -# content type defaults to application/json when not provided -test_that("req function handles default headers", { - test_req <- req("/path/to/resource") - expect_equal(test_req$headers$`Content-Type`, "application/json") - expect_equal(test_req$headers$Accept, NULL) - expect_equal(test_req$headers$Origin, NULL) -}) - - -# ------------- GET Request Tests ------------- - -test_that("GET req sends a valid GET request with valid id", { - res <- req("/archive/id/{id}", id = "ENSG00000157764") |> - httr2::req_perform() - - expect_s3_class(res, "httr2_response") - expect_equal(res$url, "https://rest.ensembl.org/archive/id/ENSG00000157764") - expect_equal(res$method, "GET") - expect_true("Content-Type" %in% names(res$headers)) - expect_equal(res$headers$`Content-Type`, "application/json") -}) - -test_that("GET req sends correct callback parameter in URL", { - res <- req("/archive/id/{id}", id = "ENSG00000157764", callback = "randomlygeneratedname") - expect_equal(res$query_params$callback, "randomlygeneratedname") - expect_match(res$url, "callback=randomlygeneratedname") -}) - -test_that("GET req sets correct headers", { - res <- req("/archive/id/{id}", id = "ENSG00000157764") - expect_equal(res$headers$`Content-Type`, "application/json") -}) - -# ------------- POST Request Tests ------------- - -## to be done +# Tests that require a connection to Ensembl's REST API. +skip_on_cran() +skip_if_offline() + +test_that("`req()` builds correct request", { + res <- "/cafe/genetree/member/symbol/{species}/{symbol}" + test_req <- req( + res, + species = "homo_sapiens", + symbol = "BRCA2", + version = NULL, + .headers = req_headers(accept = "application/json") + ) + + expected_endpoint <- "/cafe/genetree/member/symbol/homo_sapiens/BRCA2" + expect_identical(test_req$url, paste0(base_url(), expected_endpoint)) + expect_identical(test_req$headers$Accept, "application/json") + expect_identical(test_req$headers$`Accept-Encoding`, NULL) + expect_identical(test_req$headers$`Content-Type`, "application/json") + expect_identical(test_req$headers$Origin, NULL) + expect_identical(test_req$options$useragent, user_agent()) +}) + +test_that("`req()` function raises error for missing required parameters", { + + res <- "/cafe/genetree/member/symbol/{species}/{symbol}" + expect_error(req(res, species = "homo_sapiens"), "object 'symbol' not found") + expect_error(req(res, symbol = "BRCA2"), "object 'species' not found") + expect_no_error(req(res, species = "homo_sapiens", symbol = "BRCA2")) + +}) + +test_that("`req()` sets request body, if provided", { + res <- "/cafe/genetree/member/symbol/{species}/{symbol}" + test_req <- req( + res, + species = "homo_sapiens", + symbol = "BRCA2", + .body = "test body content", + .headers = req_headers(content_type = "text/plain") + ) + + expect_identical(test_req$body$data, "test body content") + expect_identical(test_req$headers$`Content-Type`, "text/plain") +}) + +# tests for optional parameters only +test_that("`req()` function handles optional parameters correctly", { + test_req <- req("/path/to/resource", + optional_param1 = "value1", + optional_param2 = "value2") + expect_identical( + test_req$url, + paste0( + base_url(), + "/path/to/resource", + "?optional_param1=", + "value1", + "&optional_param2=", + "value2" + ) + ) +}) + +test_that("`req()` function does not set body when `.body` is NULL", { + test_req <- req( + "/cafe/genetree/member/symbol/{species}/{symbol}", + species = "homo_sapiens", + symbol = "BRCA2", + .headers = req_headers(content_type = "application/json") + ) + expect_null(test_req$body) +}) + +test_that("req function handles invalid or null headers", { + test_req <- req("/path/to/resource", .headers = req_headers()) + expect_false(any(is.null(test_req$headers))) +}) + +test_that("req function correctly handles special characters in parameters", { + test_req <- req("/path", query_param = "special?chars&") + expected_url <- "https://rest.ensembl.org/path?query_param=special%3Fchars%26" + expect_identical(test_req$url, expected_url) +}) + +# in case of missing http headers argument (using defaults); +# content type defaults to application/json when not provided +test_that("req function handles default headers", { + test_req <- req("/path/to/resource") + expect_identical(test_req$headers$`Content-Type`, "application/json") + expect_null(test_req$headers$Accept) + expect_null(test_req$headers$Origin) +}) + + +# ------------- GET Request Tests ------------- + +test_that("GET req sends a valid GET request with valid id", { + res <- req("/archive/id/{id}", id = "ENSG00000157764") |> + httr2::req_perform() + + expect_s3_class(res, "httr2_response") + expect_identical(res$url, "https://rest.ensembl.org/archive/id/ENSG00000157764") + expect_identical(res$method, "GET") + expect_true("Content-Type" %in% names(res$headers)) + expect_identical(res$headers$`Content-Type`, "application/json") +}) + +test_that("GET req sends correct callback parameter in URL", { + res <- req("/archive/id/{id}", id = "ENSG00000157764", callback = "randomlygeneratedname") + expected_url <- "https://rest.ensembl.org/archive/id/ENSG00000157764?callback=randomlygeneratedname" + expect_identical(res$url, expected_url) +}) + +test_that("GET req sets correct headers", { + res <- req("/archive/id/{id}", id = "ENSG00000157764") + expect_identical(res$headers$`Content-Type`, "application/json") +}) + +# ------------- POST Request Tests ------------- + +## to be done diff --git a/tests/testthat/test-vars-in-braces.R b/tests/testthat/test-vars-in-braces.R new file mode 100644 index 0000000..3ab9808 --- /dev/null +++ b/tests/testthat/test-vars-in-braces.R @@ -0,0 +1,7 @@ +# start with basic function +test_that("vars_in_braces extracts variables correctly", { + expect_equal(vars_in_braces("Hello {world}"), "world") + expect_equal(vars_in_braces("/{species}/{symbol}"), c("species", "symbol")) + expect_equal(vars_in_braces("No braces here"), character(0)) + expect_equal(vars_in_braces("{a} {b} {c}"), c("a", "b", "c")) +}) From 42cb877c7589cc40f3ebb64c9dabf952f83964f8 Mon Sep 17 00:00:00 2001 From: danymukesha Date: Fri, 20 Sep 2024 10:54:47 +0200 Subject: [PATCH 14/28] add tests for reqs, some updates on reqs, add `get` & `post` functions --- R/gets.R | 32 +++++ R/http_headers.R | 50 ++++++++ R/posts.R | 38 ++++++ R/req.R | 150 ++++++++++++----------- tests/testthat/test-req.R | 245 +++++++++++++++++++------------------ tests/testthat/test-reqs.R | 102 +++++++++++++++ 6 files changed, 421 insertions(+), 196 deletions(-) create mode 100755 R/gets.R create mode 100755 R/http_headers.R create mode 100755 R/posts.R create mode 100755 tests/testthat/test-reqs.R diff --git a/R/gets.R b/R/gets.R new file mode 100755 index 0000000..9b3673b --- /dev/null +++ b/R/gets.R @@ -0,0 +1,32 @@ +# The function for the GET method + +get <- function(res, ..., .headers = req_headers()) { # for get the body could be optional? + requests <- reqs(res, ..., .headers = .headers) + responses <- httr2::req_perform_parallel(requests) + return(responses) +} + +## example for the get, but it will require a bit more knowledge of the APIs +# response <- get("s/archive/id/{id}", +# id = "ENSG00000139618", +# type = "genomic", +# species = "human") + +# Retrieve a given Ensembl stable ID, with a low level function +# https://rest.ensembl.org/documentation/info/archive_id_get +get_archive_id <- function(id, callback = NULL) { + if (missing(id)) { stop("The 'id' parameter is required.") } + + response <- get( + res = "/archive/id/{id}", + id = id, + #callback = callback, # optional query parameter, perferred not to use, ave to understand how it works + .headers = req_headers(content_type = "application/json") + ) + + purrr::map(response, httr2::resp_body_json) +} + +# # example +# result <- get_archive_id(id = "ENSG00000157764") +# print(result) diff --git a/R/http_headers.R b/R/http_headers.R new file mode 100755 index 0000000..41b91ae --- /dev/null +++ b/R/http_headers.R @@ -0,0 +1,50 @@ +#We can expect this R file to provide the necessary helper functios +#The reference to which headers were taken: +#https://github.com/Ensembl/ensembl-rest/wiki/HTTP-Headers + +request_headers <- + function(accept = NULL, + accept_encoding = NULL, + content_type = "application/json", + origin = NULL) { + .headers <- list( + Accept = accept, + `Accept-Encoding` = accept_encoding, + `Content-Type` = content_type, + Origin = origin + ) + + .headers <- + .headers[!sapply(.headers, is.null)] # this will remove NULL entries + + structure(.headers, class = "request_headers") + } + +response_headers <- + function(access_control_allow_origin = "*", + content_length = NULL, + content_type = "text/x-fasta", + retry_after = NULL, + x_runtime = NULL, + x_rate_limit_limit = NULL, + x_rate_limit_reset = NULL, + x_rate_limit_period = NULL, + x_rate_limit_remaining = NULL) { + + ..headers <- list( + `Access-Control-Allow-Origin` = access_control_allow_origin, + `Content-Length` = content_length, + `Content-Type` = content_type, + `Retry-After` = retry_after, + `X-Runtime` = x_runtime, + `X-RateLimit-Limit` = x_rate_limit_limit, + `X-RateLimit-Reset` = x_rate_limit_reset, + `X-RateLimit-Period` = x_rate_limit_period, + `X-RateLimit-Remaining` = x_rate_limit_remaining + ) + + ..headers <- + ..headers[!sapply(..headers, is.null)] + + structure(..headers, class = "response_headers") + } diff --git a/R/posts.R b/R/posts.R new file mode 100755 index 0000000..6cb3128 --- /dev/null +++ b/R/posts.R @@ -0,0 +1,38 @@ +#The function for POST method +post <- function(res, ..., .headers = req_headers(), .body = NULL) { + requests <- reqs(res, ..., .headers = .headers, .body = .body) + responses <- purrr::map(requests, function(req) { + req |> httr2::req_method("POST") |> + httr2::req_perform() + }) + # returns a list of responses, if multiple requests are made + responses +} + +# Retrieve the latest version for a set of Ensembl stable IDs, with a low level function +# https://rest.ensembl.org/documentation/info/archive_id_post +post_archive_ids <- function(ids, callback = NULL) { + # Validate that the 'ids' parameter is provided and is a non-empty vector + if (missing(ids) || length(ids) == 0) { + stop("The 'ids' parameter is required and should contain at least one ID.") + } + + # Create the body of the request in JSON format + body <- jsonlite::toJSON(list(id = ids), auto_unbox = TRUE) + + # Make the POST request + response <- post( + res = "/archive/id", + callback = callback, # Optional query parameter for JSONP + .headers = req_headers(content_type = "application/json"), + .body = body + ) + + # Parse and return the response as JSON + purrr::map(response, httr2::resp_body_json) +} + +# #example +# result <- post_archive_ids(ids = c("ENSG00000157764", "ENSG00000248378"), +# callback = "myCallbackFunction") +# print(result) diff --git a/R/req.R b/R/req.R index 9b9572e..e1ca75f 100755 --- a/R/req.R +++ b/R/req.R @@ -1,74 +1,76 @@ -base_url <- function() "https://rest.ensembl.org" - -user_agent <- function() "ensemblr (https://www.pattern.institute/ensemblr)" - -#' Create a new HTTP request -#' -#' [req()] creates an HTTP request object. -#' -#' @param res A resource (res) URL as a string. This string supports embedding -#' of R variable names in curly braces whose values are looked up in parameter -#' names supplied in `...` and interpolated. -#' -#' @param ... Name value pairs specifying query components or parameters. -#' -#' @param .body A literal string or raw vector to send as body. -#' -#' @param .headers An S3 list with class `ensemblr_req_hdr`. Use the helper -#' [req_headers()] to create such an object. -#' -#' @inherit httr2::request return -#' -#' @keywords internal -req <- - function(res, - ..., - .body = NULL, - .headers = req_headers()) { - - # All parameters. - params <- list(...) - pnames <- names(params) - - # Required parameters. - req_pnames <- vars_in_braces(res) - req_params <- params[req_pnames] - - # Optional parameters. - opt_pnames <- setdiff(pnames, req_pnames) - opt_params <- params[opt_pnames] - - res <- glue::glue(res, .envir = as.environment(req_params)) - - req <- - httr2::request(base_url()) |> - httr2::req_url_path_append(res) |> - httr2::req_url_query(!!!opt_params) |> - httr2::req_headers(!!!.headers) |> - httr2::req_user_agent(user_agent()) - - if (!is.null(.body)) { - req <- httr2::req_body_raw(req, body = .body, type = .headers$content_type) - } - - req - } - -reqs <- function(res, - ..., - .body = NULL, - .headers = req_headers()) { - params <- list(...) - .body <- .body %||% list(.body) - - req_args <- - vctrs::vec_recycle_common( - res = res, - !!!params, - .body = .body, - .type = .headers$content_type - ) - reqs <- purrr::pmap(.l = req_args, .f = req) - - reqs -} +base_url <- function() "https://rest.ensembl.org" + +user_agent <- function() "ensemblr (https://www.pattern.institute/ensemblr)" + +#' Create a new HTTP request +#' +#' [req()] creates an HTTP request object. +#' +#' @param res A resource (res) URL as a string. This string supports embedding +#' of R variable names in curly braces whose values are looked up in parameter +#' names supplied in `...` and interpolated. +#' +#' @param ... Name value pairs specifying query components or parameters. +#' +#' @param .body A literal string or raw vector to send as body. +#' +#' @param .headers An S3 list with class `ensemblr_req_hdr`. Use the helper +#' [req_headers()] to create such an object. +#' +#' @inherit httr2::request return +#' +#' @keywords internal +req <- + function(res, + ..., + .body = NULL, + .headers = req_headers()) { + + # All parameters. + params <- list(...) + pnames <- names(params) + + # Required parameters. + req_pnames <- vars_in_braces(res) + req_params <- params[req_pnames] + + # Optional parameters. + opt_pnames <- setdiff(pnames, req_pnames) + opt_params <- params[opt_pnames] + + res <- glue::glue(res, .envir = as.environment(req_params)) + + req <- + httr2::request(base_url()) |> + httr2::req_url_path_append(res) |> + httr2::req_url_query(!!!opt_params) |> + httr2::req_headers(!!!.headers) |> + httr2::req_user_agent(user_agent()) + + if (!is.null(.body)) { + req <- httr2::req_body_raw(req, body = .body, type = .headers$content_type) + } + + req + } + +reqs <- function(res, + ..., + .body = NULL, + .headers = req_headers()) { + params <- list(...) + .body <- .body %||% list(.body) + + req_args <- + vctrs::vec_recycle_common( + res = res, + !!!params, + .body = .body + ) + reqs <- purrr::pmap(.l = req_args, function(res, ...) { + req(res, ..., .headers = .headers) # because of errors while pass `.headers` into the recycling logic + + }) + + reqs +} diff --git a/tests/testthat/test-req.R b/tests/testthat/test-req.R index 892a173..12143c5 100755 --- a/tests/testthat/test-req.R +++ b/tests/testthat/test-req.R @@ -1,122 +1,123 @@ -# Tests that require a connection to Ensembl's REST API. -skip_on_cran() -skip_if_offline() - -test_that("`req()` builds correct request", { - res <- "/cafe/genetree/member/symbol/{species}/{symbol}" - test_req <- req( - res, - species = "homo_sapiens", - symbol = "BRCA2", - version = NULL, - .headers = req_headers(accept = "application/json") - ) - - expected_endpoint <- "/cafe/genetree/member/symbol/homo_sapiens/BRCA2" - expect_identical(test_req$url, paste0(base_url(), expected_endpoint)) - expect_identical(test_req$headers$Accept, "application/json") - expect_identical(test_req$headers$`Accept-Encoding`, NULL) - expect_identical(test_req$headers$`Content-Type`, "application/json") - expect_identical(test_req$headers$Origin, NULL) - expect_identical(test_req$options$useragent, user_agent()) -}) - -test_that("`req()` function raises error for missing required parameters", { - - res <- "/cafe/genetree/member/symbol/{species}/{symbol}" - expect_error(req(res, species = "homo_sapiens"), "object 'symbol' not found") - expect_error(req(res, symbol = "BRCA2"), "object 'species' not found") - expect_no_error(req(res, species = "homo_sapiens", symbol = "BRCA2")) - -}) - -test_that("`req()` sets request body, if provided", { - res <- "/cafe/genetree/member/symbol/{species}/{symbol}" - test_req <- req( - res, - species = "homo_sapiens", - symbol = "BRCA2", - .body = "test body content", - .headers = req_headers(content_type = "text/plain") - ) - - expect_identical(test_req$body$data, "test body content") - expect_identical(test_req$headers$`Content-Type`, "text/plain") -}) - -# tests for optional parameters only -test_that("`req()` function handles optional parameters correctly", { - test_req <- req("/path/to/resource", - optional_param1 = "value1", - optional_param2 = "value2") - expect_identical( - test_req$url, - paste0( - base_url(), - "/path/to/resource", - "?optional_param1=", - "value1", - "&optional_param2=", - "value2" - ) - ) -}) - -test_that("`req()` function does not set body when `.body` is NULL", { - test_req <- req( - "/cafe/genetree/member/symbol/{species}/{symbol}", - species = "homo_sapiens", - symbol = "BRCA2", - .headers = req_headers(content_type = "application/json") - ) - expect_null(test_req$body) -}) - -test_that("req function handles invalid or null headers", { - test_req <- req("/path/to/resource", .headers = req_headers()) - expect_false(any(is.null(test_req$headers))) -}) - -test_that("req function correctly handles special characters in parameters", { - test_req <- req("/path", query_param = "special?chars&") - expected_url <- "https://rest.ensembl.org/path?query_param=special%3Fchars%26" - expect_identical(test_req$url, expected_url) -}) - -# in case of missing http headers argument (using defaults); -# content type defaults to application/json when not provided -test_that("req function handles default headers", { - test_req <- req("/path/to/resource") - expect_identical(test_req$headers$`Content-Type`, "application/json") - expect_null(test_req$headers$Accept) - expect_null(test_req$headers$Origin) -}) - - -# ------------- GET Request Tests ------------- - -test_that("GET req sends a valid GET request with valid id", { - res <- req("/archive/id/{id}", id = "ENSG00000157764") |> - httr2::req_perform() - - expect_s3_class(res, "httr2_response") - expect_identical(res$url, "https://rest.ensembl.org/archive/id/ENSG00000157764") - expect_identical(res$method, "GET") - expect_true("Content-Type" %in% names(res$headers)) - expect_identical(res$headers$`Content-Type`, "application/json") -}) - -test_that("GET req sends correct callback parameter in URL", { - res <- req("/archive/id/{id}", id = "ENSG00000157764", callback = "randomlygeneratedname") - expected_url <- "https://rest.ensembl.org/archive/id/ENSG00000157764?callback=randomlygeneratedname" - expect_identical(res$url, expected_url) -}) - -test_that("GET req sets correct headers", { - res <- req("/archive/id/{id}", id = "ENSG00000157764") - expect_identical(res$headers$`Content-Type`, "application/json") -}) - -# ------------- POST Request Tests ------------- - -## to be done +# Tests that require a connection to Ensembl's REST API. +skip_on_cran() +skip_if_offline() + +## tests for `req()` function + +test_that("`req()` builds correct request", { + res <- "/cafe/genetree/member/symbol/{species}/{symbol}" + test_req <- req( + res, + species = "homo_sapiens", + symbol = "BRCA2", + version = NULL, + .headers = req_headers(accept = "application/json") + ) + + expected_endpoint <- "/cafe/genetree/member/symbol/homo_sapiens/BRCA2" + expect_identical(test_req$url, paste0(base_url(), expected_endpoint)) + expect_identical(test_req$headers$Accept, "application/json") + expect_identical(test_req$headers$`Accept-Encoding`, NULL) + expect_identical(test_req$headers$`Content-Type`, "application/json") + expect_identical(test_req$headers$Origin, NULL) + expect_identical(test_req$options$useragent, user_agent()) +}) + +test_that("`req()` function raises error for missing required parameters", { + + res <- "/cafe/genetree/member/symbol/{species}/{symbol}" + expect_error(req(res, species = "homo_sapiens"), "object 'symbol' not found") + expect_error(req(res, symbol = "BRCA2"), "object 'species' not found") + expect_no_error(req(res, species = "homo_sapiens", symbol = "BRCA2")) + +}) + +test_that("`req()` sets request body, if provided", { + res <- "/cafe/genetree/member/symbol/{species}/{symbol}" + test_req <- req( + res, + species = "homo_sapiens", + symbol = "BRCA2", + .body = "test body content", + .headers = req_headers(content_type = "text/plain") + ) + + expect_identical(test_req$body$data, "test body content") + expect_identical(test_req$headers$`Content-Type`, "text/plain") +}) + +# tests for optional parameters only +test_that("`req()` function handles optional parameters correctly", { + test_req <- req("/path/to/resource", + optional_param1 = "value1", + optional_param2 = "value2") + expect_identical( + test_req$url, + paste0( + base_url(), + "/path/to/resource", + "?optional_param1=", + "value1", + "&optional_param2=", + "value2" + ) + ) +}) + +test_that("`req()` function does not set body when `.body` is NULL", { + test_req <- req( + "/cafe/genetree/member/symbol/{species}/{symbol}", + species = "homo_sapiens", + symbol = "BRCA2", + .headers = req_headers(content_type = "application/json") + ) + expect_null(test_req$body) +}) + +test_that("req function handles invalid or null headers", { + test_req <- req("/path/to/resource", .headers = req_headers()) + expect_false(any(is.null(test_req$headers))) +}) + +test_that("req function correctly handles special characters in parameters", { + test_req <- req("/path", query_param = "special?chars&") + expected_url <- "https://rest.ensembl.org/path?query_param=special%3Fchars%26" + expect_identical(test_req$url, expected_url) +}) + +# in case of missing http headers argument (using defaults); +# content type defaults to application/json when not provided +test_that("req function handles default headers", { + test_req <- req("/path/to/resource") + expect_identical(test_req$headers$`Content-Type`, "application/json") + expect_null(test_req$headers$Accept) + expect_null(test_req$headers$Origin) +}) + +# ------------- GET Request Tests ------------- + +test_that("GET req sends a valid GET request with valid id", { + res <- req("/archive/id/{id}", id = "ENSG00000157764") |> + httr2::req_perform() + + expect_s3_class(res, "httr2_response") + expect_identical(res$url, "https://rest.ensembl.org/archive/id/ENSG00000157764") + expect_identical(res$method, "GET") + expect_true("Content-Type" %in% names(res$headers)) + expect_identical(res$headers$`Content-Type`, "application/json") +}) + +test_that("GET req sends correct callback parameter in URL", { + res <- req("/archive/id/{id}", id = "ENSG00000157764", callback = "randomlygeneratedname") + expected_url <- "https://rest.ensembl.org/archive/id/ENSG00000157764?callback=randomlygeneratedname" + expect_identical(res$url, expected_url) +}) + +test_that("GET req sets correct headers", { + res <- req("/archive/id/{id}", id = "ENSG00000157764") + expect_identical(res$headers$`Content-Type`, "application/json") +}) + +# ------------- POST Request Tests ------------- + +## to be done diff --git a/tests/testthat/test-reqs.R b/tests/testthat/test-reqs.R new file mode 100755 index 0000000..3fa0b28 --- /dev/null +++ b/tests/testthat/test-reqs.R @@ -0,0 +1,102 @@ +# Tests that require a connection to Ensembl's REST API. +skip_on_cran() +skip_if_offline() + +##test for only reqs() function +test_that("reqs function creates correct number of requests", { + res <- c("/endpoint1", "/endpoint2") + param1 <- c("value1", "value2") # for optional parameters + param2 <- c("a", "b") + + result <- reqs(res, param1 = param1, param2 = param2) + + expect_length(result, 2) + expect_s3_class(result[[1]], "httr2_request") #check the object type + expect_s3_class(result[[2]], "httr2_request") +}) + + +#test_that("reqs function correctly handles parameter recycling", { +# res <- c("/endpoint1", "/endpoint2", "/endpoint3") +# param1 <- c("value1", "value2") # for optional parameters +# +# result <- reqs(res, param1 = param1) +# +# expect_length(result, 3) +# expect_equal(httr2::req_url_query(result[[1]])$param1, "value1") +# expect_equal(httr2::req_url_query(result[[2]])$param1, "value2") +# expect_equal(httr2::req_url_query(result[[3]])$param1, "value1") +#}) + +test_that("reqs() correctly applies custom headers", { + res <- "/endpoint" + custom_headers <- req_headers(accept = "text/x-fasta") + + result <- reqs(res, .headers = custom_headers) + + expect_length(result, 1) + expect_equal(httr2::req_headers(result[[1]])$headers$Accept, "text/x-fasta") +}) + +#test_that("reqs() correctly interpolates variables in resource path", { +# res <- "/endpoint/{var1}/{var2}" +# var1 <- c("a", "b") +# var2 <- c("x", "y") +# +# result <- reqs(res, var1 = var1, var2 = var2) +# +# expect_length(result, 2) +# expect_match(httr2::req_url_path(result[[1]]), "/endpoint/a/x") +# expect_match(httr2::req_url_path(result[[2]]), "/endpoint/b/y") +#}) + +## more tests for `reqs()` function + +test_that("reqs() correctly vectorizes parameters", { + res_path <- "/example/resource/{param1}/{param2}" + req_list <- reqs( + res = res_path, + param1 = "value1", + param2 = c("valA", "valB"), + .headers = req_headers(content_type = "application/json") + ) + + expect_equal(length(req_list), 2) + + expect_equal(req_list[[1]]$url, + "https://rest.ensembl.org/example/resource/value1/valA") + expect_equal(req_list[[2]]$url, + "https://rest.ensembl.org/example/resource/value1/valB") + + req_list2 <- reqs( + res = res_path, + param1 = c("val1", "val2"), + param2 = c("A", "B"), + .headers = req_headers(content_type = "application/json") + ) + + expect_equal(length(req_list2), 2) + + expect_equal(req_list2[[1]]$url, + "https://rest.ensembl.org/example/resource/val1/A") + expect_equal(req_list2[[2]]$url, + "https://rest.ensembl.org/example/resource/val2/B") + + # vectorized parameters with different lengths (should throw an error) + expect_error(reqs( + res = res_path, + param1 = c("val1", "val2", "val3"), + param2 = c("A", "B"), + .headers = req_headers(content_type = "application/json") + ), "Can't recycle `res` \\(size 3\\) to match `param2` \\(size 2\\).") + + # no parameters passed (edge case) + req_list3 <- reqs( + res = "/example/resource", + .headers = req_headers(content_type = "application/json") + ) + + expect_equal(length(req_list3), 1) + expect_equal(req_list3[[1]]$url, "https://rest.ensembl.org/example/resource") +} +) From 8f6875ce59d45297c5229c5d1a9545f849a3b578 Mon Sep 17 00:00:00 2001 From: danymukesha Date: Fri, 20 Sep 2024 15:46:44 +0200 Subject: [PATCH 15/28] remove R/http_headers.R --- R/http_headers.R | 50 ------------------------------------------------ 1 file changed, 50 deletions(-) delete mode 100755 R/http_headers.R diff --git a/R/http_headers.R b/R/http_headers.R deleted file mode 100755 index 41b91ae..0000000 --- a/R/http_headers.R +++ /dev/null @@ -1,50 +0,0 @@ -#We can expect this R file to provide the necessary helper functios -#The reference to which headers were taken: -#https://github.com/Ensembl/ensembl-rest/wiki/HTTP-Headers - -request_headers <- - function(accept = NULL, - accept_encoding = NULL, - content_type = "application/json", - origin = NULL) { - .headers <- list( - Accept = accept, - `Accept-Encoding` = accept_encoding, - `Content-Type` = content_type, - Origin = origin - ) - - .headers <- - .headers[!sapply(.headers, is.null)] # this will remove NULL entries - - structure(.headers, class = "request_headers") - } - -response_headers <- - function(access_control_allow_origin = "*", - content_length = NULL, - content_type = "text/x-fasta", - retry_after = NULL, - x_runtime = NULL, - x_rate_limit_limit = NULL, - x_rate_limit_reset = NULL, - x_rate_limit_period = NULL, - x_rate_limit_remaining = NULL) { - - ..headers <- list( - `Access-Control-Allow-Origin` = access_control_allow_origin, - `Content-Length` = content_length, - `Content-Type` = content_type, - `Retry-After` = retry_after, - `X-Runtime` = x_runtime, - `X-RateLimit-Limit` = x_rate_limit_limit, - `X-RateLimit-Reset` = x_rate_limit_reset, - `X-RateLimit-Period` = x_rate_limit_period, - `X-RateLimit-Remaining` = x_rate_limit_remaining - ) - - ..headers <- - ..headers[!sapply(..headers, is.null)] - - structure(..headers, class = "response_headers") - } From a6f3c6c83cb45943ad28881f535ad27cd53180f9 Mon Sep 17 00:00:00 2001 From: danymukesha Date: Tue, 24 Sep 2024 20:26:36 +0200 Subject: [PATCH 16/28] handle rate limits on number of requests --- R/gets.R | 36 ++++++++++++++++++++++++++++++++---- R/posts.R | 41 ++++++++++++++++++++++++++++++++++++----- man/get.Rd | 28 ++++++++++++++++++++++++++++ man/post.Rd | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 9 deletions(-) create mode 100755 man/get.Rd create mode 100755 man/post.Rd diff --git a/R/gets.R b/R/gets.R index 9b3673b..3ede51b 100755 --- a/R/gets.R +++ b/R/gets.R @@ -1,12 +1,38 @@ -# The function for the GET method - -get <- function(res, ..., .headers = req_headers()) { # for get the body could be optional? +#' The function for the GET method +#' +#' The [get()] function is a wrapper around the [reqs()] function that performs +#' GET requests to the Ensembl API, handling rate limiting automatically. +#' +#' @param res The resource (path) for the API request, can include variables +#' in curly braces `{}` that will be replaced with the corresponding parameter. +#' @param ... Additional named parameters to be included in the request URL. +#' @param .headers An S3 list with class `ensemblr_req_hdr`. Use the helper +#' [req_headers()] to create such an object. +#' @param rate The maximum number of requests per second to allow. +#' Defaults to 15 per minute (15/60). +#' +#' @return A list of responses, one for each request made. +#' +#' @keywords internal +get <- function(res, ..., .headers = req_headers(), rate = 15/60) { # for get the body could be optional? requests <- reqs(res, ..., .headers = .headers) + requests <- purrr::map(requests, httr2::req_throttle, rate = rate) responses <- httr2::req_perform_parallel(requests) + + #checking the rate limit exceptions and add delay if needed + for (i in seq_along(responses)) { + if (httr2::resp_status(responses[[i]]) == 429) { + retry_after <- as.numeric(httr2::resp_headers(responses[[i]])$`Retry-After`) + message(glue::glue("Rate limit reached, waiting {retry_after} seconds before retrying...")) + Sys.sleep(retry_after) + responses[[i]] <- httr2::req_perform(requests[[i]]) + } + } return(responses) } -## example for the get, but it will require a bit more knowledge of the APIs +#---------------------------------------------------------------------------------------------- +## example for the get, but for the user it will still require a bit more knowledge of the APIs # response <- get("s/archive/id/{id}", # id = "ENSG00000139618", # type = "genomic", @@ -30,3 +56,5 @@ get_archive_id <- function(id, callback = NULL) { # # example # result <- get_archive_id(id = "ENSG00000157764") # print(result) +# +# WE CAN THEN GO ON WITH OTHER ENDPOINTS WITH GET METHOD diff --git a/R/posts.R b/R/posts.R index 6cb3128..9376024 100755 --- a/R/posts.R +++ b/R/posts.R @@ -1,14 +1,43 @@ -#The function for POST method -post <- function(res, ..., .headers = req_headers(), .body = NULL) { +#' The function for POST method +#' +#' The [post()] function is a wrapper around the [reqs()] function that +#' performs POST requests to the Ensembl API, handling rate limiting +#' automatically. +#' +#' @param res The resource (path) for the API request, can include variables +#' in curly braces `{}` that will be replaced with the corresponding +#' parameter. +#' @param ... Additional named parameters to be included in the request URL. +#' @param .body The body of the POST request, can be a string or raw vector. +#' @param .headers An S3 list with class `ensemblr_req_hdr`. Use the helper +#' [req_headers()] to create such an object. +#' @param rate The maximum number of requests per second to allow. +#' Defaults to 15 per minute (15/60). +#' +#' @return A list of responses, one for each request made. +#' +#' @keywords internal +post <- function(res, ..., .headers = req_headers(), .body, rate = 15/60) { # for post the body could be mandatory? requests <- reqs(res, ..., .headers = .headers, .body = .body) responses <- purrr::map(requests, function(req) { req |> httr2::req_method("POST") |> httr2::req_perform() }) + for (i in seq_along(responses)) { + if (httr2::resp_status(responses[[i]]) == 429) { + retry_after <- as.numeric(httr2::resp_headers(responses[[i]])$`Retry-After`) + message(glue::glue("Rate limit reached, waiting {retry_after} seconds + before retrying...")) + Sys.sleep(retry_after) + responses[[i]] <- httr2::req_perform(requests[[i]]) + } + } + # returns a list of responses, if multiple requests are made responses } +#-------------------------------------------------------------------------------------- # Retrieve the latest version for a set of Ensembl stable IDs, with a low level function # https://rest.ensembl.org/documentation/info/archive_id_post post_archive_ids <- function(ids, callback = NULL) { @@ -17,13 +46,13 @@ post_archive_ids <- function(ids, callback = NULL) { stop("The 'ids' parameter is required and should contain at least one ID.") } - # Create the body of the request in JSON format + # create the body of the request in JSON format body <- jsonlite::toJSON(list(id = ids), auto_unbox = TRUE) - # Make the POST request + # POST request response <- post( res = "/archive/id", - callback = callback, # Optional query parameter for JSONP + callback = callback, # optional query parameter for JSONP .headers = req_headers(content_type = "application/json"), .body = body ) @@ -36,3 +65,5 @@ post_archive_ids <- function(ids, callback = NULL) { # result <- post_archive_ids(ids = c("ENSG00000157764", "ENSG00000248378"), # callback = "myCallbackFunction") # print(result) +# +# WE CAN THEN GO ON WITH OTHER ENDPOINTS WITH POST METHOD diff --git a/man/get.Rd b/man/get.Rd new file mode 100755 index 0000000..5a90a10 --- /dev/null +++ b/man/get.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/gets.R +\name{get} +\alias{get} +\title{The function for the GET method} +\usage{ +get(res, ..., .headers = req_headers(), rate = 15/60) +} +\arguments{ +\item{res}{The resource (path) for the API request, can include variables +in curly braces \code{{}} that will be replaced with the corresponding parameter.} + +\item{...}{Additional named parameters to be included in the request URL.} + +\item{.headers}{An S3 list with class \code{ensemblr_req_hdr}. Use the helper +\code{\link[=req_headers]{req_headers()}} to create such an object.} + +\item{rate}{The maximum number of requests per second to allow. +Defaults to 15 per minute (15/60).} +} +\value{ +A list of responses, one for each request made. +} +\description{ +The \code{\link[=get]{get()}} function is a wrapper around the \code{\link[=reqs]{reqs()}} function that performs +GET requests to the Ensembl API, handling rate limiting automatically. +} +\keyword{internal} diff --git a/man/post.Rd b/man/post.Rd new file mode 100755 index 0000000..fca60dc --- /dev/null +++ b/man/post.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/posts.R +\name{post} +\alias{post} +\title{The function for POST method} +\usage{ +post(res, ..., .headers = req_headers(), .body, rate = 15/60) +} +\arguments{ +\item{res}{The resource (path) for the API request, can include variables +in curly braces \code{{}} that will be replaced with the corresponding +parameter.} + +\item{...}{Additional named parameters to be included in the request URL.} + +\item{.headers}{An S3 list with class \code{ensemblr_req_hdr}. Use the helper +\code{\link[=req_headers]{req_headers()}} to create such an object.} + +\item{.body}{The body of the POST request, can be a string or raw vector.} + +\item{rate}{The maximum number of requests per second to allow. +Defaults to 15 per minute (15/60).} +} +\value{ +A list of responses, one for each request made. +} +\description{ +The \code{\link[=post]{post()}} function is a wrapper around the \code{\link[=reqs]{reqs()}} function that +performs POST requests to the Ensembl API, handling rate limiting +automatically. +} +\keyword{internal} From 1c6328c87c61d58c520db81b1c0b30730f60bcf3 Mon Sep 17 00:00:00 2001 From: danymukesha Date: Thu, 26 Sep 2024 09:54:25 +0200 Subject: [PATCH 17/28] add some error handling --- R/gets.R | 11 ++++++++++- R/posts.R | 16 +++++++++++++++- man/post.Rd | 1 + 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/R/gets.R b/R/gets.R index 3ede51b..84f5289 100755 --- a/R/gets.R +++ b/R/gets.R @@ -18,14 +18,23 @@ get <- function(res, ..., .headers = req_headers(), rate = 15/60) { # for get th requests <- reqs(res, ..., .headers = .headers) requests <- purrr::map(requests, httr2::req_throttle, rate = rate) responses <- httr2::req_perform_parallel(requests) + httr2::throttle_status() #checking the rate limit exceptions and add delay if needed for (i in seq_along(responses)) { - if (httr2::resp_status(responses[[i]]) == 429) { + status_code <- httr2::resp_status(responses[[i]]) # I am not sure whether the error will arrive here + if (status_code == 200) { + break + } else if (status_code == 429) { + #the `Retry-After` in the response_headers will only show up once you exceed the rate limit retry_after <- as.numeric(httr2::resp_headers(responses[[i]])$`Retry-After`) message(glue::glue("Rate limit reached, waiting {retry_after} seconds before retrying...")) Sys.sleep(retry_after) responses[[i]] <- httr2::req_perform(requests[[i]]) + } else { + warning(glue("Request failed with status code {status_code}. + Moving on to the next request.")) + break } } return(responses) diff --git a/R/posts.R b/R/posts.R index 9376024..1762718 100755 --- a/R/posts.R +++ b/R/posts.R @@ -12,24 +12,38 @@ #' @param .headers An S3 list with class `ensemblr_req_hdr`. Use the helper #' [req_headers()] to create such an object. #' @param rate The maximum number of requests per second to allow. +#' on a request (default: 5). #' Defaults to 15 per minute (15/60). #' #' @return A list of responses, one for each request made. #' #' @keywords internal post <- function(res, ..., .headers = req_headers(), .body, rate = 15/60) { # for post the body could be mandatory? + if (missing(.body)) stop("The '.body' parameter is required for POST requests.") requests <- reqs(res, ..., .headers = .headers, .body = .body) + requests <- purrr::map(requests, httr2::req_throttle, rate = rate) responses <- purrr::map(requests, function(req) { req |> httr2::req_method("POST") |> httr2::req_perform() }) + httr2::throttle_status() + for (i in seq_along(responses)) { - if (httr2::resp_status(responses[[i]]) == 429) { + status_code <- httr2::resp_status(responses[[i]]) # I am not sure whether the error will arrive here + if (status_code == 200) { + break + } + else if (status_code == 429) { + #the `Retry-After` in the response_headers will only show up once you exceed the rate limit retry_after <- as.numeric(httr2::resp_headers(responses[[i]])$`Retry-After`) message(glue::glue("Rate limit reached, waiting {retry_after} seconds before retrying...")) Sys.sleep(retry_after) responses[[i]] <- httr2::req_perform(requests[[i]]) + } else { + warning(glue("Request failed with status code {status_code}. + Moving on to the next request.")) + break } } diff --git a/man/post.Rd b/man/post.Rd index fca60dc..ebfbf31 100755 --- a/man/post.Rd +++ b/man/post.Rd @@ -19,6 +19,7 @@ parameter.} \item{.body}{The body of the POST request, can be a string or raw vector.} \item{rate}{The maximum number of requests per second to allow. +on a request (default: 5). Defaults to 15 per minute (15/60).} } \value{ From 74af78932500139ccac8ba478517aca29db126cd Mon Sep 17 00:00:00 2001 From: danymukesha Date: Fri, 27 Sep 2024 23:32:14 +0200 Subject: [PATCH 18/28] removed unnecessary break statements --- R/gets.R | 10 +-- R/posts.R | 15 +---- tests/testthat/test-http-headers.R | 101 +++++++++++++++++++---------- 3 files changed, 71 insertions(+), 55 deletions(-) diff --git a/R/gets.R b/R/gets.R index 84f5289..91fd030 100755 --- a/R/gets.R +++ b/R/gets.R @@ -23,18 +23,14 @@ get <- function(res, ..., .headers = req_headers(), rate = 15/60) { # for get th #checking the rate limit exceptions and add delay if needed for (i in seq_along(responses)) { status_code <- httr2::resp_status(responses[[i]]) # I am not sure whether the error will arrive here - if (status_code == 200) { - break - } else if (status_code == 429) { + if (status_code == 429) { #the `Retry-After` in the response_headers will only show up once you exceed the rate limit retry_after <- as.numeric(httr2::resp_headers(responses[[i]])$`Retry-After`) message(glue::glue("Rate limit reached, waiting {retry_after} seconds before retrying...")) Sys.sleep(retry_after) responses[[i]] <- httr2::req_perform(requests[[i]]) - } else { - warning(glue("Request failed with status code {status_code}. - Moving on to the next request.")) - break + } else if (status_code != 200) { + warning(glue::glue("Request failed with status code {status_code}.")) } } return(responses) diff --git a/R/posts.R b/R/posts.R index 1762718..41f52cf 100755 --- a/R/posts.R +++ b/R/posts.R @@ -30,24 +30,18 @@ post <- function(res, ..., .headers = req_headers(), .body, rate = 15/60) { # fo for (i in seq_along(responses)) { status_code <- httr2::resp_status(responses[[i]]) # I am not sure whether the error will arrive here - if (status_code == 200) { - break - } - else if (status_code == 429) { + if (status_code == 429) { #the `Retry-After` in the response_headers will only show up once you exceed the rate limit retry_after <- as.numeric(httr2::resp_headers(responses[[i]])$`Retry-After`) message(glue::glue("Rate limit reached, waiting {retry_after} seconds before retrying...")) Sys.sleep(retry_after) responses[[i]] <- httr2::req_perform(requests[[i]]) - } else { - warning(glue("Request failed with status code {status_code}. - Moving on to the next request.")) - break + } else if (status_code != 200) { + warning(glue::glue("Request failed with status code {status_code}.")) } } - # returns a list of responses, if multiple requests are made responses } @@ -55,15 +49,12 @@ post <- function(res, ..., .headers = req_headers(), .body, rate = 15/60) { # fo # Retrieve the latest version for a set of Ensembl stable IDs, with a low level function # https://rest.ensembl.org/documentation/info/archive_id_post post_archive_ids <- function(ids, callback = NULL) { - # Validate that the 'ids' parameter is provided and is a non-empty vector if (missing(ids) || length(ids) == 0) { stop("The 'ids' parameter is required and should contain at least one ID.") } - # create the body of the request in JSON format body <- jsonlite::toJSON(list(id = ids), auto_unbox = TRUE) - # POST request response <- post( res = "/archive/id", callback = callback, # optional query parameter for JSONP diff --git a/tests/testthat/test-http-headers.R b/tests/testthat/test-http-headers.R index 614a19a..363e836 100755 --- a/tests/testthat/test-http-headers.R +++ b/tests/testthat/test-http-headers.R @@ -1,36 +1,65 @@ -test_that("req_headers creates correct structure", { - headers <- req_headers(accept = "application/json", content_type = "text/plain") - - # Check object class - expect_s3_class(headers, "ensemblr_req_hdr") - - # Check that list names match the expect header names. - expect_setequal(names(headers), req_header_names()) - - # Check that only only defined headers are different from `NULL`. - expect_named(headers[!sapply(headers, is.null)], c("Accept", "Content-Type")) - - # Check that defined headers have the assigned values. - expect_equal(headers$Accept, "application/json") - expect_equal(headers$`Content-Type`, "text/plain") -}) - -# test_that("res_headers creates correct structure", { -# headers <- response_headers(content_type = "application/json", x_runtime = "0.01") -# -# # Check that list names match the expect header names. -# expect_setequal(names(headers), res_header_names()) -# -# # Check that only only defined headers are different from `NULL`. -# expect_named(headers[!sapply(headers, is.null)], c("Accept", "Content-Type")) -# -# # Check that defined headers have the assigned values. -# expect_equal(headers$Accept, "application/json") -# expect_equal(headers$`Content-Type`, "text/plain") -# -# -# expect_s3_class(headers, "ensemblr_res_hdr") -# expect_named(headers, c("access_control_allow_origin", "content_type", "x_runtime")) -# expect_equal(headers$content_type, "application/json") -# expect_equal(headers$x_runtime, "0.01") -# }) +test_that("req_headers creates correct structure", { + headers <- req_headers(accept = "application/json", content_type = "text/plain") + + expect_s3_class(headers, "ensemblr_req_hdr") + expect_setequal(names(headers), req_header_names()) + expect_named(headers[!sapply(headers, is.null)], c("Accept", "Content-Type")) + expect_equal(headers$Accept, "application/json") + expect_equal(headers$`Content-Type`, "text/plain") +}) + +test_that("req_header_names returns the correct header names", { + expected_headers <- c("Accept", "Accept-Encoding", "Content-Type", "Origin") + expect_equal(req_header_names(), expected_headers) +}) + +test_that("res_header_names returns the correct response header names", { + expected_headers <- c( + "Access-Control-Allow-Origin", + "Content-Length", + "Content-Type", + "Retry-After", + "X-Runtime", + "X-RateLimit-Limit", + "X-RateLimit-Reset", + "X-RateLimit-Period", + "X-RateLimit-Remaining" + ) + expect_equal(res_header_names(), expected_headers) +}) + +test_that("req_headers creates a list with correct default values", { + headers <- req_headers() + expect_equal(headers$`Content-Type`, "application/json") + expect_null(headers$Accept) + expect_null(headers$`Accept-Encoding`) + expect_null(headers$Origin) + expect_s3_class(headers, "ensemblr_req_hdr") +}) + +test_that("req_headers assigns custom values correctly", { + headers <- req_headers(accept = "application/xml", origin = "https://example.com") + expect_equal(headers$Accept, "application/xml") + expect_equal(headers$Origin, "https://example.com") + expect_equal(headers$`Content-Type`, "application/json") +}) + +test_that("res_headers creates a list with correct default values", { + headers <- res_headers() + expect_equal(headers$`Access-Control-Allow-Origin`, "*") + expect_equal(headers$`Content-Type`, "application/json") + expect_null(headers$`Content-Length`) + expect_s3_class(headers, "ensemblr_res_hdr") +}) + +test_that("res_headers assigns custom values correctly", { + headers <- res_headers( + content_length = "123", + x_runtime = "0.123", + x_rate_limit_limit = "100" + ) + expect_equal(headers$`Content-Length`, "123") + expect_equal(headers$`X-Runtime`, "0.123") + expect_equal(headers$`X-RateLimit-Limit`, "100") +}) + From 3ba5684280a311a29bd164d8cd165e16936bab38 Mon Sep 17 00:00:00 2001 From: danymukesha Date: Wed, 16 Oct 2024 20:34:23 +0200 Subject: [PATCH 19/28] add low-level function for the endpoints for `Comparative Genomics` from official ensembl API, add some other updates --- NAMESPACE | 9 + R/ensembl-endpoints.R | 232 +++++++++++++++++++++++++ R/{gets.R => get.R} | 22 ++- R/{posts.R => post.R} | 6 +- man/get.Rd | 2 +- man/get_alignment_by_region.Rd | 26 +++ man/get_cafe_genetree_by_id.Rd | 27 +++ man/get_cafe_genetree_by_species_id.Rd | 27 +++ man/get_cafe_genetree_by_symbol.Rd | 31 ++++ man/get_genetree_by_id.Rd | 25 +++ man/get_genetree_by_species_id.Rd | 27 +++ man/get_genetree_by_symbol.Rd | 27 +++ man/get_homology_by_species_id.Rd | 26 +++ man/get_homology_by_symbol.Rd | 26 +++ man/post.Rd | 2 +- 15 files changed, 503 insertions(+), 12 deletions(-) mode change 100644 => 100755 NAMESPACE create mode 100755 R/ensembl-endpoints.R rename R/{gets.R => get.R} (84%) rename R/{posts.R => post.R} (94%) create mode 100755 man/get_alignment_by_region.Rd create mode 100755 man/get_cafe_genetree_by_id.Rd create mode 100755 man/get_cafe_genetree_by_species_id.Rd create mode 100755 man/get_cafe_genetree_by_symbol.Rd create mode 100755 man/get_genetree_by_id.Rd create mode 100755 man/get_genetree_by_species_id.Rd create mode 100755 man/get_genetree_by_symbol.Rd create mode 100755 man/get_homology_by_species_id.Rd create mode 100755 man/get_homology_by_symbol.Rd diff --git a/NAMESPACE b/NAMESPACE old mode 100644 new mode 100755 index 5e49a59..749bd6e --- a/NAMESPACE +++ b/NAMESPACE @@ -2,12 +2,21 @@ export("%>%") export(genomic_range) +export(get_alignment_by_region) export(get_analyses) export(get_assemblies) +export(get_cafe_genetree_by_id) +export(get_cafe_genetree_by_species_id) +export(get_cafe_genetree_by_symbol) export(get_cytogenetic_bands) export(get_data_versions) export(get_divisions) export(get_ensembl_genomes_version) +export(get_genetree_by_id) +export(get_genetree_by_species_id) +export(get_genetree_by_symbol) +export(get_homology_by_species_id) +export(get_homology_by_symbol) export(get_id) export(get_individuals) export(get_karyotypes) diff --git a/R/ensembl-endpoints.R b/R/ensembl-endpoints.R new file mode 100755 index 0000000..b112252 --- /dev/null +++ b/R/ensembl-endpoints.R @@ -0,0 +1,232 @@ +# These functions will perform validation on input parameters that are tailored +# to each specific endpoint, and return already an R object that is sensible +# for the type of information being returned by the endpoint +# ---------------------------------------------------------- + +#' Retrieves a cafe tree of the gene tree using the gene tree stable identifier +#' +#' @param id A string representing the gene tree stable identifier. +#' +#' @return A list of parsed JSON responses containing the cafe tree +#' for the provided gene tree stable identifier. +#' +#' @note +#' See more about the implemented endpoint [get_cafe_genetree_by_id()] +#' on the following [GET cafe/genetree/id/:id](https://rest.ensembl.org/documentation/info/cafe_tree) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_cafe_genetree_by_id("ENSGT00390000003602") +#' +get_cafe_genetree_by_id <- function(id) { + if (missing(id)) { + stop("The 'id' parameter is required.") + } + response <- get( + res = glue::glue("/cafe/genetree/id/{id}"), + .headers = req_headers(content_type = "application/json") + ) +} + +#' Retrieves the cafe tree of the gene tree that contains the gene identified +#' by a symbol +#' +#' @param species A string representing the species name (e.g., +#' "homo_sapiens"). +#' @param symbol A string representing the gene symbol (e.g., "BRCA2"). +#' +#' @return A list of parsed JSON responses containing the cafe tree +#' for the provided species and gene symbol. +#' +#' @note +#' See more about the implemented endpoint [get_cafe_genetree_by_symbol()] +#' on the following [GET cafe/genetree/member/symbol/:species/:symbol](https://rest.ensembl.org/documentation/info/cafe_tree_member_symbol) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_cafe_genetree_by_symbol("homo_sapiens", "BRCA2") +get_cafe_genetree_by_symbol <- function(species, symbol) { + if (missing(species) || missing(symbol)) { + stop("Both 'species' and 'symbol' parameters are required.") + } + response <- get( + res = glue::glue("/cafe/genetree/member/symbol/{species}/{symbol}"), + .headers = req_headers(content_type = "application/json") + ) + response +} + +#' Retrieves the cafe tree of the gene tree that contains the gene/transcript/translation stable identifier in the given species +#' +#' @param species A string representing the species name (e.g., "homo_sapiens"). +#' @param id A string representing the gene, transcript, or translation stable identifier. +#' +#' @return A list of parsed JSON responses containing the cafe tree for the provided species and stable identifier. +#' +#' @note +#' See more about the implemented endpoint [get_cafe_genetree_by_species_id()] +#' on the following [GET cafe/genetree/member/id/:species/:id](https://rest.ensembl.org/documentation/info/cafe_tree_species_member_id) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_cafe_genetree_by_species_id("homo_sapiens", "ENST00000380152") +get_cafe_genetree_by_species_id <- function(species, id) { + if (missing(species) || missing(id)) { + stop("Both 'species' and 'id' parameters are required.") + } + response <- get( + res = glue::glue("/cafe/genetree/member/id/{species}/{id}"), + .headers = req_headers(content_type = "application/json") + ) +} + +#' Retrieves a gene tree for a gene tree stable identifier +#' +#' @param id A string representing the gene tree stable identifier. +#' +#' @return A list of parsed JSON responses containing the gene tree for the provided gene tree stable identifier. +#' +#' @note +#' See more about the implemented endpoint [get_genetree_by_id()] +#' on the following [GET genetree/id/:id](https://rest.ensembl.org/documentation/info/genetree) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_genetree_by_id("ENSGT00390000003602") +get_genetree_by_id <- function(id) { + if (missing(id)) { + stop("The 'id' parameter is required.") + } + response <- get( + res = glue::glue("/genetree/id/{id}"), + .headers = req_headers(content_type = "application/json") + ) +} + +#' Retrieves the gene tree that contains the gene identified by a symbol +#' +#' @param species A string representing the species name (e.g., "homo_sapiens"). +#' @param symbol A string representing the gene symbol (e.g., "BRCA2"). +#' +#' @return A list of parsed JSON responses containing the gene tree for the provided species and gene symbol. +#' +#' @note +#' See more about the implemented endpoint [get_genetree_by_symbol()] +#' on the following [GET genetree/member/symbol/:species/:symbol](https://rest.ensembl.org/documentation/info/genetree_member_symbol) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_genetree_by_symbol("homo_sapiens", "BRCA2") +get_genetree_by_symbol <- function(species, symbol) { + if (missing(species) || missing(symbol)) { + stop("Both 'species' and 'symbol' parameters are required.") + } + response <- get( + res = glue::glue("/genetree/member/symbol/{species}/{symbol}"), + .headers = req_headers(content_type = "application/json") + ) +} + +#' Retrieves the gene tree that contains the gene/transcript/translation stable identifier in the given species +#' +#' @param species A string representing the species name (e.g., "homo_sapiens"). +#' @param id A string representing the gene, transcript, or translation stable identifier. +#' +#' @return A list of parsed JSON responses containing the gene tree for the provided species and stable identifier. +#' +#' @note +#' See more about the implemented endpoint [get_genetree_by_species_id()] +#' on the following [GET genetree/member/id/:species/:id](https://rest.ensembl.org/documentation/info/genetree_species_member_id) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_genetree_by_species_id("homo_sapiens", "ENST00000380152") +get_genetree_by_species_id <- function(species, id) { + if (missing(species) || missing(id)) { + stop("Both 'species' and 'id' parameters are required.") + } + response <- get( + res = glue::glue("/genetree/member/id/{species}/{id}"), + .headers = req_headers(content_type = "application/json") + ) +} + +#' Retrieves genomic alignments as separate blocks based on a region and species +#' +#' @param species A string representing the species name (e.g., "homo_sapiens"). +#' @param region A string representing the genomic region (e.g., "3:1000-2000"). +#' +#' @return A list of parsed JSON responses containing the genomic alignments for the provided species and region. +#' +#' See more about the implemented endpoint [get_alignment_by_region()] +#' on the following [GET alignment/region/:species/:region](https://rest.ensembl.org/documentation/info/genomic_alignment_region) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_alignment_by_region("homo_sapiens", "3:1000-2000") +get_alignment_by_region <- function(species, region) { + warning("This function is stil under-develop. If you run it now + it will return you an error.") + if (missing(species) || missing(region)) { + stop("Both 'species' and 'region' parameters are required.") + } + # response <- get( + # res = glue::glue("/alignment/region/{species}/{region}"), + # .headers = req_headers(content_type = "application/json") + # ) +} + +#' Retrieves homology information (orthologs) by species and Ensembl gene ID +#' +#' @param species A string representing the species name (e.g., "homo_sapiens"). +#' @param id A string representing the Ensembl gene ID. +#' +#' @return A list of parsed JSON responses containing homology information for the provided species and Ensembl gene ID. +#' +#' See more about the implemented endpoint [get_homology_by_species_id()] +#' on the following [GET homology/id/:species/:id](https://rest.ensembl.org/documentation/info/homology_species_gene_id) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_homology_by_species_id("homo_sapiens", "ENSG00000157764") +get_homology_by_species_id <- function(species, id) { + if (missing(species) || missing(id)) { + stop("Both 'species' and 'id' parameters are required.") + } + response <- get( + res = glue::glue("/homology/id/{species}/{id}"), + .headers = req_headers(content_type = "application/json") + ) +} + +#' Retrieves homology information (orthologs) by species and symbol +#' +#' @param species A string representing the species name (e.g., "homo_sapiens"). +#' @param symbol A string representing the gene symbol (e.g., "BRCA2"). +#' +#' @return A list of parsed JSON responses containing homology information for the provided species and gene symbol. +#' +#' See more about the implemented endpoint [get_homology_by_symbol()] +#' on the following [GET homology/symbol/:species/:symbol](https://rest.ensembl.org/documentation/info/homology_symbol) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_homology_by_symbol("homo_sapiens", "BRCA2") +get_homology_by_symbol <- function(species, symbol) { + if (missing(species) || missing(symbol)) { + stop("Both 'species' and 'symbol' parameters are required.") + } + response <- get( + res = glue::glue("/homology/symbol/{species}/{symbol}"), + .headers = req_headers(content_type = "application/json") + ) +} diff --git a/R/gets.R b/R/get.R similarity index 84% rename from R/gets.R rename to R/get.R index 91fd030..75f7184 100755 --- a/R/gets.R +++ b/R/get.R @@ -38,7 +38,7 @@ get <- function(res, ..., .headers = req_headers(), rate = 15/60) { # for get th #---------------------------------------------------------------------------------------------- ## example for the get, but for the user it will still require a bit more knowledge of the APIs -# response <- get("s/archive/id/{id}", +# response <- get("/archive/id/{id}", # id = "ENSG00000139618", # type = "genomic", # species = "human") @@ -46,20 +46,30 @@ get <- function(res, ..., .headers = req_headers(), rate = 15/60) { # for get th # Retrieve a given Ensembl stable ID, with a low level function # https://rest.ensembl.org/documentation/info/archive_id_get get_archive_id <- function(id, callback = NULL) { - if (missing(id)) { stop("The 'id' parameter is required.") } - + if (missing(id)) { + stop("The 'id' parameter is required.") + } response <- get( res = "/archive/id/{id}", id = id, #callback = callback, # optional query parameter, perferred not to use, ave to understand how it works .headers = req_headers(content_type = "application/json") ) - - purrr::map(response, httr2::resp_body_json) } # # example # result <- get_archive_id(id = "ENSG00000157764") # print(result) -# + +get_cafe_genetree_by_id <- function(id) { + if (missing(id)) { + stop("The 'id' parameter is required.") + } + response <- get( + res = glue::glue("/cafe/genetree/id/{id}"), + .headers = req_headers(content_type = "application/json") + ) +} + # WE CAN THEN GO ON WITH OTHER ENDPOINTS WITH GET METHOD +# {the rest of the endpoints functions are in file `ensembl-endpoins.R`} diff --git a/R/posts.R b/R/post.R similarity index 94% rename from R/posts.R rename to R/post.R index 41f52cf..e256187 100755 --- a/R/posts.R +++ b/R/post.R @@ -61,14 +61,12 @@ post_archive_ids <- function(ids, callback = NULL) { .headers = req_headers(content_type = "application/json"), .body = body ) - - # Parse and return the response as JSON - purrr::map(response, httr2::resp_body_json) } # #example # result <- post_archive_ids(ids = c("ENSG00000157764", "ENSG00000248378"), # callback = "myCallbackFunction") # print(result) -# + # WE CAN THEN GO ON WITH OTHER ENDPOINTS WITH POST METHOD +# {the rest of the endpoints functions are in file `ensembl-endpoins.R`} diff --git a/man/get.Rd b/man/get.Rd index 5a90a10..e2947b2 100755 --- a/man/get.Rd +++ b/man/get.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gets.R +% Please edit documentation in R/get.R \name{get} \alias{get} \title{The function for the GET method} diff --git a/man/get_alignment_by_region.Rd b/man/get_alignment_by_region.Rd new file mode 100755 index 0000000..4f230e0 --- /dev/null +++ b/man/get_alignment_by_region.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_alignment_by_region} +\alias{get_alignment_by_region} +\title{Retrieves genomic alignments as separate blocks based on a region and species} +\usage{ +get_alignment_by_region(species, region) +} +\arguments{ +\item{species}{A string representing the species name (e.g., "homo_sapiens").} + +\item{region}{A string representing the genomic region (e.g., "3:1000-2000").} +} +\value{ +A list of parsed JSON responses containing the genomic alignments for the provided species and region. + +See more about the implemented endpoint \code{\link[=get_alignment_by_region]{get_alignment_by_region()}} +on the following \href{https://rest.ensembl.org/documentation/info/genomic_alignment_region}{GET alignment/region/:species/:region} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves genomic alignments as separate blocks based on a region and species +} +\examples{ +get_alignment_by_region("homo_sapiens", "3:1000-2000") +} diff --git a/man/get_cafe_genetree_by_id.Rd b/man/get_cafe_genetree_by_id.Rd new file mode 100755 index 0000000..3d9419e --- /dev/null +++ b/man/get_cafe_genetree_by_id.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_cafe_genetree_by_id} +\alias{get_cafe_genetree_by_id} +\title{Retrieves a cafe tree of the gene tree using the gene tree stable identifier} +\usage{ +get_cafe_genetree_by_id(id) +} +\arguments{ +\item{id}{A string representing the gene tree stable identifier.} +} +\value{ +A list of parsed JSON responses containing the cafe tree +for the provided gene tree stable identifier. +} +\description{ +Retrieves a cafe tree of the gene tree using the gene tree stable identifier +} +\note{ +See more about the implemented endpoint \code{\link[=get_cafe_genetree_by_id]{get_cafe_genetree_by_id()}} +on the following \href{https://rest.ensembl.org/documentation/info/cafe_tree}{GET cafe/genetree/id/:id} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\examples{ +get_cafe_genetree_by_id("ENSGT00390000003602") + +} diff --git a/man/get_cafe_genetree_by_species_id.Rd b/man/get_cafe_genetree_by_species_id.Rd new file mode 100755 index 0000000..3290774 --- /dev/null +++ b/man/get_cafe_genetree_by_species_id.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_cafe_genetree_by_species_id} +\alias{get_cafe_genetree_by_species_id} +\title{Retrieves the cafe tree of the gene tree that contains the gene/transcript/translation stable identifier in the given species} +\usage{ +get_cafe_genetree_by_species_id(species, id) +} +\arguments{ +\item{species}{A string representing the species name (e.g., "homo_sapiens").} + +\item{id}{A string representing the gene, transcript, or translation stable identifier.} +} +\value{ +A list of parsed JSON responses containing the cafe tree for the provided species and stable identifier. +} +\description{ +Retrieves the cafe tree of the gene tree that contains the gene/transcript/translation stable identifier in the given species +} +\note{ +See more about the implemented endpoint \code{\link[=get_cafe_genetree_by_species_id]{get_cafe_genetree_by_species_id()}} +on the following \href{https://rest.ensembl.org/documentation/info/cafe_tree_species_member_id}{GET cafe/genetree/member/id/:species/:id} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\examples{ +get_cafe_genetree_by_species_id("homo_sapiens", "ENST00000380152") +} diff --git a/man/get_cafe_genetree_by_symbol.Rd b/man/get_cafe_genetree_by_symbol.Rd new file mode 100755 index 0000000..966c9a6 --- /dev/null +++ b/man/get_cafe_genetree_by_symbol.Rd @@ -0,0 +1,31 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_cafe_genetree_by_symbol} +\alias{get_cafe_genetree_by_symbol} +\title{Retrieves the cafe tree of the gene tree that contains the gene identified +by a symbol} +\usage{ +get_cafe_genetree_by_symbol(species, symbol) +} +\arguments{ +\item{species}{A string representing the species name (e.g., +"homo_sapiens").} + +\item{symbol}{A string representing the gene symbol (e.g., "BRCA2").} +} +\value{ +A list of parsed JSON responses containing the cafe tree +for the provided species and gene symbol. +} +\description{ +Retrieves the cafe tree of the gene tree that contains the gene identified +by a symbol +} +\note{ +See more about the implemented endpoint \code{\link[=get_cafe_genetree_by_symbol]{get_cafe_genetree_by_symbol()}} +on the following \href{https://rest.ensembl.org/documentation/info/cafe_tree_member_symbol}{GET cafe/genetree/member/symbol/:species/:symbol} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\examples{ +get_cafe_genetree_by_symbol("homo_sapiens", "BRCA2") +} diff --git a/man/get_genetree_by_id.Rd b/man/get_genetree_by_id.Rd new file mode 100755 index 0000000..fadd40f --- /dev/null +++ b/man/get_genetree_by_id.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_genetree_by_id} +\alias{get_genetree_by_id} +\title{Retrieves a gene tree for a gene tree stable identifier} +\usage{ +get_genetree_by_id(id) +} +\arguments{ +\item{id}{A string representing the gene tree stable identifier.} +} +\value{ +A list of parsed JSON responses containing the gene tree for the provided gene tree stable identifier. +} +\description{ +Retrieves a gene tree for a gene tree stable identifier +} +\note{ +See more about the implemented endpoint \code{\link[=get_genetree_by_id]{get_genetree_by_id()}} +on the following \href{https://rest.ensembl.org/documentation/info/genetree}{GET genetree/id/:id} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\examples{ +get_genetree_by_id("ENSGT00390000003602") +} diff --git a/man/get_genetree_by_species_id.Rd b/man/get_genetree_by_species_id.Rd new file mode 100755 index 0000000..248c704 --- /dev/null +++ b/man/get_genetree_by_species_id.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_genetree_by_species_id} +\alias{get_genetree_by_species_id} +\title{Retrieves the gene tree that contains the gene/transcript/translation stable identifier in the given species} +\usage{ +get_genetree_by_species_id(species, id) +} +\arguments{ +\item{species}{A string representing the species name (e.g., "homo_sapiens").} + +\item{id}{A string representing the gene, transcript, or translation stable identifier.} +} +\value{ +A list of parsed JSON responses containing the gene tree for the provided species and stable identifier. +} +\description{ +Retrieves the gene tree that contains the gene/transcript/translation stable identifier in the given species +} +\note{ +See more about the implemented endpoint \code{\link[=get_genetree_by_species_id]{get_genetree_by_species_id()}} +on the following \href{https://rest.ensembl.org/documentation/info/genetree_species_member_id}{GET genetree/member/id/:species/:id} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\examples{ +get_genetree_by_species_id("homo_sapiens", "ENST00000380152") +} diff --git a/man/get_genetree_by_symbol.Rd b/man/get_genetree_by_symbol.Rd new file mode 100755 index 0000000..acd0cb5 --- /dev/null +++ b/man/get_genetree_by_symbol.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_genetree_by_symbol} +\alias{get_genetree_by_symbol} +\title{Retrieves the gene tree that contains the gene identified by a symbol} +\usage{ +get_genetree_by_symbol(species, symbol) +} +\arguments{ +\item{species}{A string representing the species name (e.g., "homo_sapiens").} + +\item{symbol}{A string representing the gene symbol (e.g., "BRCA2").} +} +\value{ +A list of parsed JSON responses containing the gene tree for the provided species and gene symbol. +} +\description{ +Retrieves the gene tree that contains the gene identified by a symbol +} +\note{ +See more about the implemented endpoint \code{\link[=get_genetree_by_symbol]{get_genetree_by_symbol()}} +on the following \href{https://rest.ensembl.org/documentation/info/genetree_member_symbol}{GET genetree/member/symbol/:species/:symbol} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\examples{ +get_genetree_by_symbol("homo_sapiens", "BRCA2") +} diff --git a/man/get_homology_by_species_id.Rd b/man/get_homology_by_species_id.Rd new file mode 100755 index 0000000..d63603a --- /dev/null +++ b/man/get_homology_by_species_id.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_homology_by_species_id} +\alias{get_homology_by_species_id} +\title{Retrieves homology information (orthologs) by species and Ensembl gene ID} +\usage{ +get_homology_by_species_id(species, id) +} +\arguments{ +\item{species}{A string representing the species name (e.g., "homo_sapiens").} + +\item{id}{A string representing the Ensembl gene ID.} +} +\value{ +A list of parsed JSON responses containing homology information for the provided species and Ensembl gene ID. + +See more about the implemented endpoint \code{\link[=get_homology_by_species_id]{get_homology_by_species_id()}} +on the following \href{https://rest.ensembl.org/documentation/info/homology_species_gene_id}{GET homology/id/:species/:id} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves homology information (orthologs) by species and Ensembl gene ID +} +\examples{ +get_homology_by_species_id("homo_sapiens", "ENSG00000157764") +} diff --git a/man/get_homology_by_symbol.Rd b/man/get_homology_by_symbol.Rd new file mode 100755 index 0000000..a230b13 --- /dev/null +++ b/man/get_homology_by_symbol.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_homology_by_symbol} +\alias{get_homology_by_symbol} +\title{Retrieves homology information (orthologs) by species and symbol} +\usage{ +get_homology_by_symbol(species, symbol) +} +\arguments{ +\item{species}{A string representing the species name (e.g., "homo_sapiens").} + +\item{symbol}{A string representing the gene symbol (e.g., "BRCA2").} +} +\value{ +A list of parsed JSON responses containing homology information for the provided species and gene symbol. + +See more about the implemented endpoint \code{\link[=get_homology_by_symbol]{get_homology_by_symbol()}} +on the following \href{https://rest.ensembl.org/documentation/info/homology_symbol}{GET homology/symbol/:species/:symbol} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves homology information (orthologs) by species and symbol +} +\examples{ +get_homology_by_symbol("homo_sapiens", "BRCA2") +} diff --git a/man/post.Rd b/man/post.Rd index ebfbf31..d7da7b8 100755 --- a/man/post.Rd +++ b/man/post.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/posts.R +% Please edit documentation in R/post.R \name{post} \alias{post} \title{The function for POST method} From 8834ca974724f3bbbf8118094194aa061fb20404 Mon Sep 17 00:00:00 2001 From: danymukesha Date: Fri, 18 Oct 2024 11:58:21 +0200 Subject: [PATCH 20/28] started `Cross References` and add some small updates --- R/ensembl-endpoints.R | 29 ++++++++++++++++++++++++-- man/get_alignment_by_region.Rd | 2 +- man/get_cafe_genetree_by_id.Rd | 2 +- man/get_cafe_genetree_by_species_id.Rd | 2 +- man/get_cafe_genetree_by_symbol.Rd | 3 +-- man/get_genetree_by_id.Rd | 2 +- man/get_genetree_by_species_id.Rd | 2 +- man/get_genetree_by_symbol.Rd | 2 +- man/get_homology_by_species_id.Rd | 2 +- man/get_homology_by_symbol.Rd | 2 +- 10 files changed, 36 insertions(+), 12 deletions(-) diff --git a/R/ensembl-endpoints.R b/R/ensembl-endpoints.R index b112252..6014462 100755 --- a/R/ensembl-endpoints.R +++ b/R/ensembl-endpoints.R @@ -1,8 +1,12 @@ # These functions will perform validation on input parameters that are tailored # to each specific endpoint, and return already an R object that is sensible # for the type of information being returned by the endpoint -# ---------------------------------------------------------- +# -------------------------------------------------------- # +# Endpoints ==== +## Comparative Genomics ===== +#' Get cafe gene tree by id +#' #' Retrieves a cafe tree of the gene tree using the gene tree stable identifier #' #' @param id A string representing the gene tree stable identifier. @@ -29,6 +33,8 @@ get_cafe_genetree_by_id <- function(id) { ) } +#' Get cafe gene tree by symbol +#' #' Retrieves the cafe tree of the gene tree that contains the gene identified #' by a symbol #' @@ -55,9 +61,10 @@ get_cafe_genetree_by_symbol <- function(species, symbol) { res = glue::glue("/cafe/genetree/member/symbol/{species}/{symbol}"), .headers = req_headers(content_type = "application/json") ) - response } +#' Get cafe gene tree by species id +#' #' Retrieves the cafe tree of the gene tree that contains the gene/transcript/translation stable identifier in the given species #' #' @param species A string representing the species name (e.g., "homo_sapiens"). @@ -83,6 +90,8 @@ get_cafe_genetree_by_species_id <- function(species, id) { ) } +#' Get gene tree by id +#' #' Retrieves a gene tree for a gene tree stable identifier #' #' @param id A string representing the gene tree stable identifier. @@ -107,6 +116,8 @@ get_genetree_by_id <- function(id) { ) } +#' Get gene tree by symbol +#' #' Retrieves the gene tree that contains the gene identified by a symbol #' #' @param species A string representing the species name (e.g., "homo_sapiens"). @@ -132,6 +143,8 @@ get_genetree_by_symbol <- function(species, symbol) { ) } +#' Get gene tree by species id +#' #' Retrieves the gene tree that contains the gene/transcript/translation stable identifier in the given species #' #' @param species A string representing the species name (e.g., "homo_sapiens"). @@ -157,6 +170,8 @@ get_genetree_by_species_id <- function(species, id) { ) } +#' Get alignment by region +#' #' Retrieves genomic alignments as separate blocks based on a region and species #' #' @param species A string representing the species name (e.g., "homo_sapiens"). @@ -183,6 +198,8 @@ get_alignment_by_region <- function(species, region) { # ) } +#' Get homologous by species id +#' #' Retrieves homology information (orthologs) by species and Ensembl gene ID #' #' @param species A string representing the species name (e.g., "homo_sapiens"). @@ -207,6 +224,8 @@ get_homology_by_species_id <- function(species, id) { ) } +#' Get homologous by symbol +#' #' Retrieves homology information (orthologs) by species and symbol #' #' @param species A string representing the species name (e.g., "homo_sapiens"). @@ -230,3 +249,9 @@ get_homology_by_symbol <- function(species, symbol) { .headers = req_headers(content_type = "application/json") ) } + +# -------------------------------------------------------- # +## Cross References ==== + + + diff --git a/man/get_alignment_by_region.Rd b/man/get_alignment_by_region.Rd index 4f230e0..4897ca3 100755 --- a/man/get_alignment_by_region.Rd +++ b/man/get_alignment_by_region.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/ensembl-endpoints.R \name{get_alignment_by_region} \alias{get_alignment_by_region} -\title{Retrieves genomic alignments as separate blocks based on a region and species} +\title{Get alignment by region} \usage{ get_alignment_by_region(species, region) } diff --git a/man/get_cafe_genetree_by_id.Rd b/man/get_cafe_genetree_by_id.Rd index 3d9419e..3f51303 100755 --- a/man/get_cafe_genetree_by_id.Rd +++ b/man/get_cafe_genetree_by_id.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/ensembl-endpoints.R \name{get_cafe_genetree_by_id} \alias{get_cafe_genetree_by_id} -\title{Retrieves a cafe tree of the gene tree using the gene tree stable identifier} +\title{Get cafe gene tree by id} \usage{ get_cafe_genetree_by_id(id) } diff --git a/man/get_cafe_genetree_by_species_id.Rd b/man/get_cafe_genetree_by_species_id.Rd index 3290774..8051daa 100755 --- a/man/get_cafe_genetree_by_species_id.Rd +++ b/man/get_cafe_genetree_by_species_id.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/ensembl-endpoints.R \name{get_cafe_genetree_by_species_id} \alias{get_cafe_genetree_by_species_id} -\title{Retrieves the cafe tree of the gene tree that contains the gene/transcript/translation stable identifier in the given species} +\title{Get cafe gene tree by species id} \usage{ get_cafe_genetree_by_species_id(species, id) } diff --git a/man/get_cafe_genetree_by_symbol.Rd b/man/get_cafe_genetree_by_symbol.Rd index 966c9a6..5bdc7ac 100755 --- a/man/get_cafe_genetree_by_symbol.Rd +++ b/man/get_cafe_genetree_by_symbol.Rd @@ -2,8 +2,7 @@ % Please edit documentation in R/ensembl-endpoints.R \name{get_cafe_genetree_by_symbol} \alias{get_cafe_genetree_by_symbol} -\title{Retrieves the cafe tree of the gene tree that contains the gene identified -by a symbol} +\title{Get cafe gene tree by symbol} \usage{ get_cafe_genetree_by_symbol(species, symbol) } diff --git a/man/get_genetree_by_id.Rd b/man/get_genetree_by_id.Rd index fadd40f..5915b5d 100755 --- a/man/get_genetree_by_id.Rd +++ b/man/get_genetree_by_id.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/ensembl-endpoints.R \name{get_genetree_by_id} \alias{get_genetree_by_id} -\title{Retrieves a gene tree for a gene tree stable identifier} +\title{Get gene tree by id} \usage{ get_genetree_by_id(id) } diff --git a/man/get_genetree_by_species_id.Rd b/man/get_genetree_by_species_id.Rd index 248c704..97bed0b 100755 --- a/man/get_genetree_by_species_id.Rd +++ b/man/get_genetree_by_species_id.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/ensembl-endpoints.R \name{get_genetree_by_species_id} \alias{get_genetree_by_species_id} -\title{Retrieves the gene tree that contains the gene/transcript/translation stable identifier in the given species} +\title{Get gene tree by species id} \usage{ get_genetree_by_species_id(species, id) } diff --git a/man/get_genetree_by_symbol.Rd b/man/get_genetree_by_symbol.Rd index acd0cb5..f7a517f 100755 --- a/man/get_genetree_by_symbol.Rd +++ b/man/get_genetree_by_symbol.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/ensembl-endpoints.R \name{get_genetree_by_symbol} \alias{get_genetree_by_symbol} -\title{Retrieves the gene tree that contains the gene identified by a symbol} +\title{Get gene tree by symbol} \usage{ get_genetree_by_symbol(species, symbol) } diff --git a/man/get_homology_by_species_id.Rd b/man/get_homology_by_species_id.Rd index d63603a..4122b83 100755 --- a/man/get_homology_by_species_id.Rd +++ b/man/get_homology_by_species_id.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/ensembl-endpoints.R \name{get_homology_by_species_id} \alias{get_homology_by_species_id} -\title{Retrieves homology information (orthologs) by species and Ensembl gene ID} +\title{Get homologous by species id} \usage{ get_homology_by_species_id(species, id) } diff --git a/man/get_homology_by_symbol.Rd b/man/get_homology_by_symbol.Rd index a230b13..4e26488 100755 --- a/man/get_homology_by_symbol.Rd +++ b/man/get_homology_by_symbol.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/ensembl-endpoints.R \name{get_homology_by_symbol} \alias{get_homology_by_symbol} -\title{Retrieves homology information (orthologs) by species and symbol} +\title{Get homologous by symbol} \usage{ get_homology_by_symbol(species, symbol) } From 788a4f29fd8a5c821c9be6b2c16b18168a766ce9 Mon Sep 17 00:00:00 2001 From: danymukesha Date: Fri, 18 Oct 2024 17:20:47 +0200 Subject: [PATCH 21/28] add low-level functions for the endpoints for `Cross References` from official ensembl API, and unit tests --- NAMESPACE | 3 + R/ensembl-endpoints.R | 142 ++++++++++++++++++++++++++++-- man/get_alignment_by_region.Rd | 3 +- man/get_genetree_by_species_id.Rd | 9 +- man/get_genetree_by_symbol.Rd | 3 +- man/get_homology_by_species_id.Rd | 3 +- man/get_homology_by_symbol.Rd | 3 +- man/get_xrefs_by_id.Rd | 26 ++++++ man/get_xrefs_by_name.Rd | 29 ++++++ man/get_xrefs_by_symbol.Rd | 33 +++++++ tests/testthat/test-endpoints.R | 92 +++++++++++++++++++ 11 files changed, 332 insertions(+), 14 deletions(-) create mode 100755 man/get_xrefs_by_id.Rd create mode 100755 man/get_xrefs_by_name.Rd create mode 100755 man/get_xrefs_by_symbol.Rd create mode 100755 tests/testthat/test-endpoints.R diff --git a/NAMESPACE b/NAMESPACE index 749bd6e..c28f26d 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -35,6 +35,9 @@ export(get_variation_sources) export(get_versioning) export(get_xrefs_by_ensembl_id) export(get_xrefs_by_gene) +export(get_xrefs_by_id) +export(get_xrefs_by_name) +export(get_xrefs_by_symbol) export(is_ensembl_reachable) importFrom(magrittr,"%>%") importFrom(rlang,.data) diff --git a/R/ensembl-endpoints.R b/R/ensembl-endpoints.R index 6014462..1239feb 100755 --- a/R/ensembl-endpoints.R +++ b/R/ensembl-endpoints.R @@ -123,7 +123,8 @@ get_genetree_by_id <- function(id) { #' @param species A string representing the species name (e.g., "homo_sapiens"). #' @param symbol A string representing the gene symbol (e.g., "BRCA2"). #' -#' @return A list of parsed JSON responses containing the gene tree for the provided species and gene symbol. +#' @return A list of parsed JSON responses containing the gene tree +#' for the provided species and gene symbol. #' #' @note #' See more about the implemented endpoint [get_genetree_by_symbol()] @@ -145,12 +146,15 @@ get_genetree_by_symbol <- function(species, symbol) { #' Get gene tree by species id #' -#' Retrieves the gene tree that contains the gene/transcript/translation stable identifier in the given species +#' Retrieves the gene tree that contains the gene/transcript/translation +#' stable identifier in the given species #' #' @param species A string representing the species name (e.g., "homo_sapiens"). -#' @param id A string representing the gene, transcript, or translation stable identifier. +#' @param id A string representing the gene, transcript, or translation stable +#' identifier. #' -#' @return A list of parsed JSON responses containing the gene tree for the provided species and stable identifier. +#' @return A list of parsed JSON responses containing the gene tree +#' for the provided species and stable identifier. #' #' @note #' See more about the implemented endpoint [get_genetree_by_species_id()] @@ -177,7 +181,8 @@ get_genetree_by_species_id <- function(species, id) { #' @param species A string representing the species name (e.g., "homo_sapiens"). #' @param region A string representing the genomic region (e.g., "3:1000-2000"). #' -#' @return A list of parsed JSON responses containing the genomic alignments for the provided species and region. +#' @return A list of parsed JSON responses containing the genomic alignments +#' for the provided species and region. #' #' See more about the implemented endpoint [get_alignment_by_region()] #' on the following [GET alignment/region/:species/:region](https://rest.ensembl.org/documentation/info/genomic_alignment_region) @@ -205,7 +210,8 @@ get_alignment_by_region <- function(species, region) { #' @param species A string representing the species name (e.g., "homo_sapiens"). #' @param id A string representing the Ensembl gene ID. #' -#' @return A list of parsed JSON responses containing homology information for the provided species and Ensembl gene ID. +#' @return A list of parsed JSON responses containing homology information +#' for the provided species and Ensembl gene ID. #' #' See more about the implemented endpoint [get_homology_by_species_id()] #' on the following [GET homology/id/:species/:id](https://rest.ensembl.org/documentation/info/homology_species_gene_id) @@ -231,7 +237,8 @@ get_homology_by_species_id <- function(species, id) { #' @param species A string representing the species name (e.g., "homo_sapiens"). #' @param symbol A string representing the gene symbol (e.g., "BRCA2"). #' -#' @return A list of parsed JSON responses containing homology information for the provided species and gene symbol. +#' @return A list of parsed JSON responses containing homology information +#' for the provided species and gene symbol. #' #' See more about the implemented endpoint [get_homology_by_symbol()] #' on the following [GET homology/symbol/:species/:symbol](https://rest.ensembl.org/documentation/info/homology_symbol) @@ -253,5 +260,126 @@ get_homology_by_symbol <- function(species, symbol) { # -------------------------------------------------------- # ## Cross References ==== +#' Get external linked references by symbol +#' +#' Looks up an external symbol and returns all Ensembl objects linked to it +#' +#' This can be a display name for a gene/transcript/translation, a synonym, +#' or an externally linked reference. +#' If a gene's transcript is linked to the supplied symbol, the service will +#' return both gene and transcript (it supports transient links). +#' +#' @param species A string representing the species name (e.g., "homo_sapiens"). +#' @param symbol A string representing the external symbol (e.g., "BRCA2"). +#' +#' @return A list of parsed JSON responses containing Ensembl objects linked +#' to the provided external symbol. +#' +#' See more about the implemented endpoint [get_xrefs_by_symbol()] +#' on the following [GET xrefs/symbol/:species/:symbol](https://rest.ensembl.org/documentation/info/xref_external) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_xrefs_by_symbol("homo_sapiens", "BRCA2") +get_xrefs_by_symbol <- function(species, symbol) { + if (missing(species) || missing(symbol)) { + stop("Both 'species' and 'symbol' parameters are required.") + } + response <- get( + res = glue::glue("/xrefs/symbol/{species}/{symbol}"), + .headers = req_headers(content_type = "application/json") + ) +} +#' Get external linked references by id +#' +#' Performs lookups of Ensembl Identifiers and retrieves their external +#' references in other databases +#' +#' @param id A string representing the Ensembl Identifier (e.g., "ENSG00000157764"). +#' +#' @return A list of parsed JSON responses containing external references +#' for the provided Ensembl identifier. +#' +#' See more about the implemented endpoint [get_xrefs_by_id()] +#' on the following [GET xrefs/id/:id](https://rest.ensembl.org/documentation/info/xref_id) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_xrefs_by_id("ENSG00000157764") +get_xrefs_by_id <- function(id) { + if (missing(id)) { + stop("The 'id' parameter is required.") + } + response <- get( + res = glue::glue("/xrefs/id/{id}"), + .headers = req_headers(content_type = "application/json") + ) +} +#' Get external linked references by name +#' +#' Performs a lookup based upon the primary accession or display label +#' of an external reference +#' +#' @param species A string representing the species name (e.g., "homo_sapiens"). +#' @param name A string representing the primary accession or display label +#' of the external reference. +#' +#' @return A list of parsed JSON responses containing information about +#' the provided external reference. +#' +#' See more about the implemented endpoint [get_xrefs_by_name()] +#' on the following [GET xrefs/name/:species/:name](https://rest.ensembl.org/documentation/info/xref_name) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_xrefs_by_name("homo_sapiens", "P38398") +get_xrefs_by_name <- function(species, name) { + if (missing(species) || missing(name)) { + stop("Both 'species' and 'name' parameters are required.") + } + response <- get( + res = glue::glue("/xrefs/name/{species}/{name}"), + .headers = req_headers(content_type = "application/json") + ) +} + +# -------------------------------------------------------- # +## Information ==== + +# -------------------------------------------------------- # +## Linkage Disequilibrium ==== + +# -------------------------------------------------------- # +## Lookup ==== + +# -------------------------------------------------------- # +## Mapping ==== + +# -------------------------------------------------------- # +## Ontologies and taxonomy ==== + +# -------------------------------------------------------- # +## Overlap ==== + +# -------------------------------------------------------- # +## Phenotype annotations ==== + +# -------------------------------------------------------- # +## Regulation ==== + +# -------------------------------------------------------- # +## Transcript Haplotypes ==== + +# -------------------------------------------------------- # +## VEP ==== + +# -------------------------------------------------------- # +## Variation ==== + +# -------------------------------------------------------- # +## Variation GA4GH ==== diff --git a/man/get_alignment_by_region.Rd b/man/get_alignment_by_region.Rd index 4897ca3..dbbd35f 100755 --- a/man/get_alignment_by_region.Rd +++ b/man/get_alignment_by_region.Rd @@ -12,7 +12,8 @@ get_alignment_by_region(species, region) \item{region}{A string representing the genomic region (e.g., "3:1000-2000").} } \value{ -A list of parsed JSON responses containing the genomic alignments for the provided species and region. +A list of parsed JSON responses containing the genomic alignments +for the provided species and region. See more about the implemented endpoint \code{\link[=get_alignment_by_region]{get_alignment_by_region()}} on the following \href{https://rest.ensembl.org/documentation/info/genomic_alignment_region}{GET alignment/region/:species/:region} diff --git a/man/get_genetree_by_species_id.Rd b/man/get_genetree_by_species_id.Rd index 97bed0b..5fc14ae 100755 --- a/man/get_genetree_by_species_id.Rd +++ b/man/get_genetree_by_species_id.Rd @@ -9,13 +9,16 @@ get_genetree_by_species_id(species, id) \arguments{ \item{species}{A string representing the species name (e.g., "homo_sapiens").} -\item{id}{A string representing the gene, transcript, or translation stable identifier.} +\item{id}{A string representing the gene, transcript, or translation stable +identifier.} } \value{ -A list of parsed JSON responses containing the gene tree for the provided species and stable identifier. +A list of parsed JSON responses containing the gene tree +for the provided species and stable identifier. } \description{ -Retrieves the gene tree that contains the gene/transcript/translation stable identifier in the given species +Retrieves the gene tree that contains the gene/transcript/translation +stable identifier in the given species } \note{ See more about the implemented endpoint \code{\link[=get_genetree_by_species_id]{get_genetree_by_species_id()}} diff --git a/man/get_genetree_by_symbol.Rd b/man/get_genetree_by_symbol.Rd index f7a517f..69f515c 100755 --- a/man/get_genetree_by_symbol.Rd +++ b/man/get_genetree_by_symbol.Rd @@ -12,7 +12,8 @@ get_genetree_by_symbol(species, symbol) \item{symbol}{A string representing the gene symbol (e.g., "BRCA2").} } \value{ -A list of parsed JSON responses containing the gene tree for the provided species and gene symbol. +A list of parsed JSON responses containing the gene tree +for the provided species and gene symbol. } \description{ Retrieves the gene tree that contains the gene identified by a symbol diff --git a/man/get_homology_by_species_id.Rd b/man/get_homology_by_species_id.Rd index 4122b83..903a36e 100755 --- a/man/get_homology_by_species_id.Rd +++ b/man/get_homology_by_species_id.Rd @@ -12,7 +12,8 @@ get_homology_by_species_id(species, id) \item{id}{A string representing the Ensembl gene ID.} } \value{ -A list of parsed JSON responses containing homology information for the provided species and Ensembl gene ID. +A list of parsed JSON responses containing homology information +for the provided species and Ensembl gene ID. See more about the implemented endpoint \code{\link[=get_homology_by_species_id]{get_homology_by_species_id()}} on the following \href{https://rest.ensembl.org/documentation/info/homology_species_gene_id}{GET homology/id/:species/:id} diff --git a/man/get_homology_by_symbol.Rd b/man/get_homology_by_symbol.Rd index 4e26488..b13f9b2 100755 --- a/man/get_homology_by_symbol.Rd +++ b/man/get_homology_by_symbol.Rd @@ -12,7 +12,8 @@ get_homology_by_symbol(species, symbol) \item{symbol}{A string representing the gene symbol (e.g., "BRCA2").} } \value{ -A list of parsed JSON responses containing homology information for the provided species and gene symbol. +A list of parsed JSON responses containing homology information +for the provided species and gene symbol. See more about the implemented endpoint \code{\link[=get_homology_by_symbol]{get_homology_by_symbol()}} on the following \href{https://rest.ensembl.org/documentation/info/homology_symbol}{GET homology/symbol/:species/:symbol} diff --git a/man/get_xrefs_by_id.Rd b/man/get_xrefs_by_id.Rd new file mode 100755 index 0000000..cfb1285 --- /dev/null +++ b/man/get_xrefs_by_id.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_xrefs_by_id} +\alias{get_xrefs_by_id} +\title{Get external linked references by id} +\usage{ +get_xrefs_by_id(id) +} +\arguments{ +\item{id}{A string representing the Ensembl Identifier (e.g., "ENSG00000157764").} +} +\value{ +A list of parsed JSON responses containing external references +for the provided Ensembl identifier. + +See more about the implemented endpoint \code{\link[=get_xrefs_by_id]{get_xrefs_by_id()}} +on the following \href{https://rest.ensembl.org/documentation/info/xref_id}{GET xrefs/id/:id} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Performs lookups of Ensembl Identifiers and retrieves their external +references in other databases +} +\examples{ +get_xrefs_by_id("ENSG00000157764") +} diff --git a/man/get_xrefs_by_name.Rd b/man/get_xrefs_by_name.Rd new file mode 100755 index 0000000..360e3e5 --- /dev/null +++ b/man/get_xrefs_by_name.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_xrefs_by_name} +\alias{get_xrefs_by_name} +\title{Get external linked references by name} +\usage{ +get_xrefs_by_name(species, name) +} +\arguments{ +\item{species}{A string representing the species name (e.g., "homo_sapiens").} + +\item{name}{A string representing the primary accession or display label +of the external reference.} +} +\value{ +A list of parsed JSON responses containing information about +the provided external reference. + +See more about the implemented endpoint \code{\link[=get_xrefs_by_name]{get_xrefs_by_name()}} +on the following \href{https://rest.ensembl.org/documentation/info/xref_name}{GET xrefs/name/:species/:name} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Performs a lookup based upon the primary accession or display label +of an external reference +} +\examples{ +get_xrefs_by_name("homo_sapiens", "P38398") +} diff --git a/man/get_xrefs_by_symbol.Rd b/man/get_xrefs_by_symbol.Rd new file mode 100755 index 0000000..82ef8ec --- /dev/null +++ b/man/get_xrefs_by_symbol.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_xrefs_by_symbol} +\alias{get_xrefs_by_symbol} +\title{Get external linked references by symbol} +\usage{ +get_xrefs_by_symbol(species, symbol) +} +\arguments{ +\item{species}{A string representing the species name (e.g., "homo_sapiens").} + +\item{symbol}{A string representing the external symbol (e.g., "BRCA2").} +} +\value{ +A list of parsed JSON responses containing Ensembl objects linked +to the provided external symbol. + +See more about the implemented endpoint \code{\link[=get_xrefs_by_symbol]{get_xrefs_by_symbol()}} +on the following \href{https://rest.ensembl.org/documentation/info/xref_external}{GET xrefs/symbol/:species/:symbol} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Looks up an external symbol and returns all Ensembl objects linked to it +} +\details{ +This can be a display name for a gene/transcript/translation, a synonym, +or an externally linked reference. +If a gene's transcript is linked to the supplied symbol, the service will +return both gene and transcript (it supports transient links). +} +\examples{ +get_xrefs_by_symbol("homo_sapiens", "BRCA2") +} diff --git a/tests/testthat/test-endpoints.R b/tests/testthat/test-endpoints.R new file mode 100755 index 0000000..cc47779 --- /dev/null +++ b/tests/testthat/test-endpoints.R @@ -0,0 +1,92 @@ +skip_on_cran() +skip_if_offline() + +test_that("Testing if the `Ensembl API` functions work correctly", { + + ## Comparative Genomics ==== + + test_that("`get_cafe_genetree_by_id` works", { + result <- get_cafe_genetree_by_id("ENSGT00390000003602") + expect_type(result, "list") + expect_equal(result[[1]]$status_code, 200) + expect_error(get_cafe_genetree_by_id(), "The 'id' parameter is required") + }) + + test_that("`get_cafe_genetree_by_symbol` works", { + result <- get_cafe_genetree_by_symbol("homo_sapiens", "BRCA2") + expect_type(result, "list") + expect_equal(result[[1]]$status_code, 200) + expect_error(get_cafe_genetree_by_symbol("homo_sapiens"), "Both 'species' and 'symbol' parameters are required") + }) + + test_that("`get_cafe_genetree_by_species_id` works", { + result <- get_cafe_genetree_by_species_id("homo_sapiens", "ENST00000380152") + expect_type(result, "list") + expect_equal(result[[1]]$status_code, 200) + expect_error(get_cafe_genetree_by_species_id("homo_sapiens"), "Both 'species' and 'id' parameters are required") + }) + + test_that("`get_genetree_by_id` works", { + result <- get_genetree_by_id("ENSGT00390000003602") + expect_type(result, "list") + expect_equal(result[[1]]$status_code, 200) + expect_error(get_genetree_by_id(), "The 'id' parameter is required") + }) + + test_that("`get_genetree_by_symbol` works", { + result <- get_genetree_by_symbol("homo_sapiens", "BRCA2") + expect_type(result, "list") + expect_equal(result[[1]]$status_code, 200) + expect_error(get_genetree_by_symbol("homo_sapiens"), "Both 'species' and 'symbol' parameters are required") + }) + + test_that("`get_genetree_by_species_id` works", { + result <- get_genetree_by_species_id("homo_sapiens", "ENST00000380152") + expect_type(result, "list") + expect_equal(result[[1]]$status_code, 200) + expect_error(get_genetree_by_species_id("homo_sapiens"), "Both 'species' and 'id' parameters are required") + }) + + test_that("`get_alignment_by_region` works", { + expect_warning(get_alignment_by_region("homo_sapiens", "3:1000-2000"), "This function is stil under-develop") + # expect_error(get_alignment_by_region("homo_sapiens"), "Both 'species' and 'region' parameters are required") + }) + + test_that("`get_homology_by_species_id` works", { + result <- get_homology_by_species_id("homo_sapiens", "ENSG00000157764") + expect_type(result, "list") + expect_equal(result[[1]]$status_code, 200) + expect_error(get_homology_by_species_id("homo_sapiens"), "Both 'species' and 'id' parameters are required") + }) + + test_that("`get_homology_by_symbol` works", { + result <- get_homology_by_symbol("homo_sapiens", "BRCA2") + expect_type(result, "list") + expect_equal(result[[1]]$status_code, 200) + expect_error(get_homology_by_symbol("homo_sapiens"), "Both 'species' and 'symbol' parameters are required") + }) + + ## Cross References ==== + + test_that("`get_xrefs_by_symbol` works", { + result <- get_xrefs_by_symbol("homo_sapiens", "BRCA2") + expect_type(result, "list") + expect_equal(result[[1]]$status_code, 200) + expect_error(get_xrefs_by_symbol("homo_sapiens"), "Both 'species' and 'symbol' parameters are required") + }) + + test_that("`get_xrefs_by_id` works", { + result <- get_xrefs_by_id("ENSG00000157764") + expect_type(result, "list") + expect_equal(result[[1]]$status_code, 200) + expect_error(get_xrefs_by_id(), "The 'id' parameter is required") + }) + + test_that("`get_xrefs_by_name` works", { + result <- get_xrefs_by_name("homo_sapiens", "P38398") + expect_type(result, "list") + expect_equal(result[[1]]$status_code, 200) + expect_error(get_xrefs_by_name("homo_sapiens"), "Both 'species' and 'name' parameters are required") + }) + +}) From 33b1b231bd839d1e8da89c2ed300536a57a5c7f8 Mon Sep 17 00:00:00 2001 From: danymukesha Date: Wed, 20 Nov 2024 20:19:40 +0100 Subject: [PATCH 22/28] Re-wrote the already existing functions from `versioning.R` --- NAMESPACE | 4 ++ R/api-versioning.R | 90 ++++++++++++++++++++++++++++++++++++ man/get_data_version2.Rd | 23 +++++++++ man/get_rest_version2.Rd | 25 ++++++++++ man/get_software_version2.Rd | 23 +++++++++ man/get_versioning2.Rd | 34 ++++++++++++++ 6 files changed, 199 insertions(+) create mode 100755 R/api-versioning.R create mode 100755 man/get_data_version2.Rd create mode 100755 man/get_rest_version2.Rd create mode 100755 man/get_software_version2.Rd create mode 100755 man/get_versioning2.Rd diff --git a/NAMESPACE b/NAMESPACE index c28f26d..422732a 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -9,6 +9,7 @@ export(get_cafe_genetree_by_id) export(get_cafe_genetree_by_species_id) export(get_cafe_genetree_by_symbol) export(get_cytogenetic_bands) +export(get_data_version2) export(get_data_versions) export(get_divisions) export(get_ensembl_genomes_version) @@ -26,13 +27,16 @@ export(get_ld_variants_by_range) export(get_ld_variants_by_window) export(get_populations) export(get_rest_version) +export(get_rest_version2) export(get_software_version) +export(get_software_version2) export(get_species) export(get_toplevel_sequence_info) export(get_toplevel_sequences) export(get_variant_consequences) export(get_variation_sources) export(get_versioning) +export(get_versioning2) export(get_xrefs_by_ensembl_id) export(get_xrefs_by_gene) export(get_xrefs_by_id) diff --git a/R/api-versioning.R b/R/api-versioning.R new file mode 100755 index 0000000..66403ee --- /dev/null +++ b/R/api-versioning.R @@ -0,0 +1,90 @@ +##----Re-wrote the already existing functions from `version.R`---- + +#' Get REST API version +#' +#' Retrieve the version of the Ensembl REST API currently in use. +#' The version format is `major.minor.point`. +#' @return A list containing the REST API version components: +#' `major`, `minor`, and `point`. +#' @source \url{https://github.com/Ensembl/ensembl-rest/wiki/API-Versioning} +#' @examples +#' \dontrun{ +#' rest_version <- get_rest_version() +#' print(rest_version) +#' } +#' @export +get_rest_version2 <- function() { + res <- "info/rest" + version <- ensemblr:::get(res)[[1]] |> + httr2::resp_body_json() + version$release +} + +#' Get data version +#' +#' Retreive the version(s) of the Ensembl data that the REST API is accessing. +#' @return A numeric vector of data release versions. +#' @source \url{https://github.com/Ensembl/ensembl-rest/wiki/API-Versioning} +#' @examples +#' \dontrun{ +#' data_version <- get_data_version() +#' print(data_version) +#' } +#' @export +get_data_version2 <- function() { + res <- "info/data" + version <- ensemblr:::get(res)[[1]] |> + httr2::resp_body_json() + version$release |> as.numeric() +} + +#' Get API software version +#' +#' Retreive the version of the Ensembl software the REST API is using. +#' @return A numeric value representing the software version. +#' @source \url{https://github.com/Ensembl/ensembl-rest/wiki/API-Versioning} +#' @examples +#' \dontrun{ +#' software_version <- get_software_version() +#' print(software_version) +#' } +#' @export +get_software_version2 <- function() { + res <- "info/data" + version <- ensemblr:::get(res)[[1]] |> + httr2::resp_body_json() + version$release |> as.numeric() +} + +#' Get Ensembl REST versions +#' +#' Retreive the versions of the different entities involved in the +#' REST API requests. When accessing the Ensembl REST API, you are actually +#' accessing three interconnected entities: +#' \itemize{ +#' \item Ensembl databases (\code{data}). +#' \item Perl API (\code{software}). +#' \item REST API (\code{rest}). +#' } +#' \figure{ensembl_api_versioning_wo_fonts.svg} +#' +#' @return A named list of three elements: \code{data}, \code{software} and +#' \code{rest}. +#' +#' @examples +#' # Get the versions of the different entities involved in the REST API +#' # requests. +#' get_versioning() +#' +#' @export +get_versioning2 <- function() { + data_version <- get_data_version2() + software_version <- get_software_version2() + rest_version <- get_rest_version2() + + api_versions <- list(data = data_version, + software = software_version, + rest = rest_version) + + return(api_versions) +} diff --git a/man/get_data_version2.Rd b/man/get_data_version2.Rd new file mode 100755 index 0000000..5251d92 --- /dev/null +++ b/man/get_data_version2.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/api-versioning.R +\name{get_data_version2} +\alias{get_data_version2} +\title{Get data version} +\source{ +\url{https://github.com/Ensembl/ensembl-rest/wiki/API-Versioning} +} +\usage{ +get_data_version2() +} +\value{ +A numeric vector of data release versions. +} +\description{ +Retreive the version(s) of the Ensembl data that the REST API is accessing. +} +\examples{ +\dontrun{ +data_version <- get_data_version() +print(data_version) +} +} diff --git a/man/get_rest_version2.Rd b/man/get_rest_version2.Rd new file mode 100755 index 0000000..a393683 --- /dev/null +++ b/man/get_rest_version2.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/api-versioning.R +\name{get_rest_version2} +\alias{get_rest_version2} +\title{Get REST API version} +\source{ +\url{https://github.com/Ensembl/ensembl-rest/wiki/API-Versioning} +} +\usage{ +get_rest_version2() +} +\value{ +A list containing the REST API version components: +\code{major}, \code{minor}, and \code{point}. +} +\description{ +Retrieve the version of the Ensembl REST API currently in use. +The version format is \code{major.minor.point}. +} +\examples{ +\dontrun{ +rest_version <- get_rest_version() +print(rest_version) +} +} diff --git a/man/get_software_version2.Rd b/man/get_software_version2.Rd new file mode 100755 index 0000000..ef746cc --- /dev/null +++ b/man/get_software_version2.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/api-versioning.R +\name{get_software_version2} +\alias{get_software_version2} +\title{Get API software version} +\source{ +\url{https://github.com/Ensembl/ensembl-rest/wiki/API-Versioning} +} +\usage{ +get_software_version2() +} +\value{ +A numeric value representing the software version. +} +\description{ +Retreive the version of the Ensembl software the REST API is using. +} +\examples{ +\dontrun{ +software_version <- get_software_version() +print(software_version) +} +} diff --git a/man/get_versioning2.Rd b/man/get_versioning2.Rd new file mode 100755 index 0000000..756744c --- /dev/null +++ b/man/get_versioning2.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/api-versioning.R +\name{get_versioning2} +\alias{get_versioning2} +\title{Get Ensembl REST versions} +\usage{ +get_versioning2() +} +\arguments{ +\item{verbose}{Whether to be chatty.} + +\item{warnings}{Whether to print warnings.} +} +\value{ +A named list of three elements: \code{data}, \code{software} and +\code{rest}. +} +\description{ +Retreive the versions of the different entities involved in the +REST API requests. When accessing the Ensembl REST API, you are actually +accessing three interconnected entities: +\itemize{ +\item Ensembl databases (\code{data}). +\item Perl API (\code{software}). +\item REST API (\code{rest}). +} +\figure{ensembl_api_versioning_wo_fonts.svg} +} +\examples{ +# Get the versions of the different entities involved in the REST API +# requests. +get_versioning() + +} From 501240da77f124d0ac8347b5102537a247b9c4c2 Mon Sep 17 00:00:00 2001 From: danymukesha Date: Wed, 20 Nov 2024 20:31:22 +0100 Subject: [PATCH 23/28] correct some bugs --- R/api-versioning.R | 8 ++++---- man/get_data_version2.Rd | 2 +- man/get_rest_version2.Rd | 2 +- man/get_versioning2.Rd | 5 ----- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/R/api-versioning.R b/R/api-versioning.R index 66403ee..fe07a13 100755 --- a/R/api-versioning.R +++ b/R/api-versioning.R @@ -1,10 +1,10 @@ -##----Re-wrote the already existing functions from `version.R`---- +##----Re-wrote the already existing functions from `versioning.R`---- #' Get REST API version #' #' Retrieve the version of the Ensembl REST API currently in use. #' The version format is `major.minor.point`. -#' @return A list containing the REST API version components: +#' @return A numeric value representing the REST API version components: #' `major`, `minor`, and `point`. #' @source \url{https://github.com/Ensembl/ensembl-rest/wiki/API-Versioning} #' @examples @@ -23,7 +23,7 @@ get_rest_version2 <- function() { #' Get data version #' #' Retreive the version(s) of the Ensembl data that the REST API is accessing. -#' @return A numeric vector of data release versions. +#' @return A numeric value representing of data release version. #' @source \url{https://github.com/Ensembl/ensembl-rest/wiki/API-Versioning} #' @examples #' \dontrun{ @@ -50,7 +50,7 @@ get_data_version2 <- function() { #' } #' @export get_software_version2 <- function() { - res <- "info/data" + res <- "info/software" version <- ensemblr:::get(res)[[1]] |> httr2::resp_body_json() version$release |> as.numeric() diff --git a/man/get_data_version2.Rd b/man/get_data_version2.Rd index 5251d92..3024a9e 100755 --- a/man/get_data_version2.Rd +++ b/man/get_data_version2.Rd @@ -10,7 +10,7 @@ get_data_version2() } \value{ -A numeric vector of data release versions. +A numeric value representing of data release version. } \description{ Retreive the version(s) of the Ensembl data that the REST API is accessing. diff --git a/man/get_rest_version2.Rd b/man/get_rest_version2.Rd index a393683..d8e0224 100755 --- a/man/get_rest_version2.Rd +++ b/man/get_rest_version2.Rd @@ -10,7 +10,7 @@ get_rest_version2() } \value{ -A list containing the REST API version components: +A numeric value representing the REST API version components: \code{major}, \code{minor}, and \code{point}. } \description{ diff --git a/man/get_versioning2.Rd b/man/get_versioning2.Rd index 756744c..5da0871 100755 --- a/man/get_versioning2.Rd +++ b/man/get_versioning2.Rd @@ -6,11 +6,6 @@ \usage{ get_versioning2() } -\arguments{ -\item{verbose}{Whether to be chatty.} - -\item{warnings}{Whether to print warnings.} -} \value{ A named list of three elements: \code{data}, \code{software} and \code{rest}. From 6a812216e29fa673347b0ddb991a39b9197111b0 Mon Sep 17 00:00:00 2001 From: danymukesha Date: Wed, 4 Dec 2024 19:29:26 +0100 Subject: [PATCH 24/28] remove `glue::glue` from the end-points functions and passed all tests --- R/ensembl-endpoints.R | 48 ++++--- R/versioning.R | 214 ++++++++++++++++---------------- man/get_rest_version.Rd | 0 man/get_software_version.Rd | 0 tests/testthat/test-endpoints.R | 7 ++ 5 files changed, 137 insertions(+), 132 deletions(-) mode change 100644 => 100755 R/versioning.R mode change 100644 => 100755 man/get_rest_version.Rd mode change 100644 => 100755 man/get_software_version.Rd diff --git a/R/ensembl-endpoints.R b/R/ensembl-endpoints.R index 1239feb..22e006b 100755 --- a/R/ensembl-endpoints.R +++ b/R/ensembl-endpoints.R @@ -27,8 +27,7 @@ get_cafe_genetree_by_id <- function(id) { if (missing(id)) { stop("The 'id' parameter is required.") } - response <- get( - res = glue::glue("/cafe/genetree/id/{id}"), + response <- get(res = "/cafe/genetree/id/{id}", id = id, .headers = req_headers(content_type = "application/json") ) } @@ -57,9 +56,9 @@ get_cafe_genetree_by_symbol <- function(species, symbol) { if (missing(species) || missing(symbol)) { stop("Both 'species' and 'symbol' parameters are required.") } - response <- get( - res = glue::glue("/cafe/genetree/member/symbol/{species}/{symbol}"), - .headers = req_headers(content_type = "application/json") + response <- get(res = "/cafe/genetree/member/symbol/{species}/{symbol}", + species = species, symbol = symbol, + symbol = symbol, .headers = req_headers(content_type = "application/json") ) } @@ -84,8 +83,8 @@ get_cafe_genetree_by_species_id <- function(species, id) { if (missing(species) || missing(id)) { stop("Both 'species' and 'id' parameters are required.") } - response <- get( - res = glue::glue("/cafe/genetree/member/id/{species}/{id}"), + response <- get(res = "/cafe/genetree/member/id/{species}/{id}", + species = species, id = id, .headers = req_headers(content_type = "application/json") ) } @@ -110,8 +109,7 @@ get_genetree_by_id <- function(id) { if (missing(id)) { stop("The 'id' parameter is required.") } - response <- get( - res = glue::glue("/genetree/id/{id}"), + response <- get(res = "/genetree/id/{id}", id = id, .headers = req_headers(content_type = "application/json") ) } @@ -138,8 +136,8 @@ get_genetree_by_symbol <- function(species, symbol) { if (missing(species) || missing(symbol)) { stop("Both 'species' and 'symbol' parameters are required.") } - response <- get( - res = glue::glue("/genetree/member/symbol/{species}/{symbol}"), + response <- get(res = "/genetree/member/symbol/{species}/{symbol}", + species = species, symbol = symbol, .headers = req_headers(content_type = "application/json") ) } @@ -168,8 +166,8 @@ get_genetree_by_species_id <- function(species, id) { if (missing(species) || missing(id)) { stop("Both 'species' and 'id' parameters are required.") } - response <- get( - res = glue::glue("/genetree/member/id/{species}/{id}"), + response <- get(res = "/genetree/member/id/{species}/{id}", + species = species, id = id, .headers = req_headers(content_type = "application/json") ) } @@ -197,8 +195,8 @@ get_alignment_by_region <- function(species, region) { if (missing(species) || missing(region)) { stop("Both 'species' and 'region' parameters are required.") } - # response <- get( - # res = glue::glue("/alignment/region/{species}/{region}"), + # response <- get(res = "/alignment/region/{species}/{region}", + # species = species, region = region, # .headers = req_headers(content_type = "application/json") # ) } @@ -224,8 +222,8 @@ get_homology_by_species_id <- function(species, id) { if (missing(species) || missing(id)) { stop("Both 'species' and 'id' parameters are required.") } - response <- get( - res = glue::glue("/homology/id/{species}/{id}"), + response <- get(res = "/homology/id/{species}/{id}", + species = species, id = id, .headers = req_headers(content_type = "application/json") ) } @@ -251,8 +249,8 @@ get_homology_by_symbol <- function(species, symbol) { if (missing(species) || missing(symbol)) { stop("Both 'species' and 'symbol' parameters are required.") } - response <- get( - res = glue::glue("/homology/symbol/{species}/{symbol}"), + response <- get("/homology/symbol/{species}/{symbol}", + species = species, symbol = symbol, .headers = req_headers(content_type = "application/json") ) } @@ -286,8 +284,8 @@ get_xrefs_by_symbol <- function(species, symbol) { if (missing(species) || missing(symbol)) { stop("Both 'species' and 'symbol' parameters are required.") } - response <- get( - res = glue::glue("/xrefs/symbol/{species}/{symbol}"), + response <- get(res = "/xrefs/symbol/{species}/{symbol}", + species = species, symbol = symbol, .headers = req_headers(content_type = "application/json") ) } @@ -313,8 +311,8 @@ get_xrefs_by_id <- function(id) { if (missing(id)) { stop("The 'id' parameter is required.") } - response <- get( - res = glue::glue("/xrefs/id/{id}"), + response <- get(res = "/xrefs/id/{id}", + id = id, .headers = req_headers(content_type = "application/json") ) } @@ -342,8 +340,8 @@ get_xrefs_by_name <- function(species, name) { if (missing(species) || missing(name)) { stop("Both 'species' and 'name' parameters are required.") } - response <- get( - res = glue::glue("/xrefs/name/{species}/{name}"), + response <- get(res = "/xrefs/name/{species}/{name}", + species = species, name = name, .headers = req_headers(content_type = "application/json") ) } diff --git a/R/versioning.R b/R/versioning.R old mode 100644 new mode 100755 index 16285eb..4584e0b --- a/R/versioning.R +++ b/R/versioning.R @@ -1,107 +1,107 @@ -#' Retrieve the Perl API version -#' -#' @param verbose Whether to be chatty. -#' @param warnings Whether to print warnings. -#' @return A scalar integer vector with the Perl API version. -#' -#' @export -get_software_version <- function(verbose = FALSE, warnings = TRUE) { - - response <- request( - resource_url = '/info/software?', - verbose = verbose, - warnings = warnings) - - return(purrr::pluck(response, - 'content', - 'release', - .default = NA_integer_) - ) -} - -#' Retrieve the current version of the Ensembl REST API -#' -#' @param verbose Whether to be chatty. -#' @param warnings Whether to print warnings. -#' @return A scalar character vector with Ensembl REST API version. -#' -#' @export -get_rest_version <- function(verbose = FALSE, warnings = TRUE) { - - response <- request( - resource_url = '/info/rest?', - verbose = verbose, - warnings = warnings) - - return(purrr::pluck(response, - 'content', - 'release', - .default = NA_character_) - ) -} - -#' Retrieve the data release version(s) available on the Ensembl REST server. -#' -#' @param verbose Whether to be chatty. -#' @param warnings Whether to print warnings. -#' @return An integer vector of release version(s). -#' -#' @export -get_data_versions <- function(verbose = FALSE, warnings = TRUE) { - - response <- request( - resource_url = '/info/data?', - verbose = verbose, - warnings = warnings) - - return(purrr::pluck(response, - 'content', - 'releases', - .default = NA_integer_) - ) -} - -#' Retrieve Ensembl REST versions -#' -#' This function gets the versions of the different entities involved in the -#' REST API requests. When accessing the Ensembl REST API, you are actually -#' accessing three interconnected entities: -#' \itemize{ -#' \item Ensembl databases (\code{data}). -#' \item Perl API (\code{software}). -#' \item REST API (\code{rest}). -#' } -#' \figure{ensembl_api_versioning_wo_fonts.svg} -#' -#' @param verbose Whether to be chatty. -#' @param warnings Whether to print warnings. -#' @return A named list of three elements: \code{data}, \code{software} and -#' \code{rest}. -#' -#' @examples -#' # Get the versions of the different entities involved in the REST API -#' # requests. -#' get_versioning() -#' -#' @export -get_versioning <- function(verbose = FALSE, warnings = TRUE) { - - # Ensembl data release version(s) - data_version <- - get_data_versions(verbose = verbose, warnings = warnings) - - # Ensembl internal Perl API version - software_version <- - get_software_version(verbose = verbose, warnings = warnings) - - # Ensembl REST API version - rest_version <- - get_rest_version(verbose = verbose, warnings = warnings) - - api_versions <- list( - data = data_version, - software = software_version, - rest = rest_version) - - return(api_versions) -} +#' Retrieve the Perl API version +#' +#' @param verbose Whether to be chatty. +#' @param warnings Whether to print warnings. +#' @return A scalar integer vector with the Perl API version. +#' +#' @export +get_software_version <- function(verbose = FALSE, warnings = TRUE) { + + response <- request( + resource_url = '/info/software?', + verbose = verbose, + warnings = warnings) + + return(purrr::pluck(response, + 'content', + 'release', + .default = NA_integer_) + ) +} + +#' Retrieve the current version of the Ensembl REST API +#' +#' @param verbose Whether to be chatty. +#' @param warnings Whether to print warnings. +#' @return A scalar character vector with Ensembl REST API version. +#' +#' @export +get_rest_version <- function(verbose = FALSE, warnings = TRUE) { + + response <- request( + resource_url = '/info/rest?', + verbose = verbose, + warnings = warnings) + + return(purrr::pluck(response, + 'content', + 'release', + .default = NA_character_) + ) +} + +#' Retrieve the data release version(s) available on the Ensembl REST server. +#' +#' @param verbose Whether to be chatty. +#' @param warnings Whether to print warnings. +#' @return An integer vector of release version(s). +#' +#' @export +get_data_versions <- function(verbose = FALSE, warnings = TRUE) { + + response <- request( + resource_url = '/info/data?', + verbose = verbose, + warnings = warnings) + + return(purrr::pluck(response, + 'content', + 'releases', + .default = NA_integer_) + ) +} + +#' Retrieve Ensembl REST versions +#' +#' This function gets the versions of the different entities involved in the +#' REST API requests. When accessing the Ensembl REST API, you are actually +#' accessing three interconnected entities: +#' \itemize{ +#' \item Ensembl databases (\code{data}). +#' \item Perl API (\code{software}). +#' \item REST API (\code{rest}). +#' } +#' \figure{ensembl_api_versioning_wo_fonts.svg} +#' +#' @param verbose Whether to be chatty. +#' @param warnings Whether to print warnings. +#' @return A named list of three elements: \code{data}, \code{software} and +#' \code{rest}. +#' +#' @examples +#' # Get the versions of the different entities involved in the REST API +#' # requests. +#' get_versioning() +#' +#' @export +get_versioning <- function(verbose = FALSE, warnings = TRUE) { + + # Ensembl data release version(s) + data_version <- + get_data_versions(verbose = verbose, warnings = warnings) + + # Ensembl internal Perl API version + software_version <- + get_software_version(verbose = verbose, warnings = warnings) + + # Ensembl REST API version + rest_version <- + get_rest_version(verbose = verbose, warnings = warnings) + + api_versions <- list( + data = data_version, + software = software_version, + rest = rest_version) + + return(api_versions) +} diff --git a/man/get_rest_version.Rd b/man/get_rest_version.Rd old mode 100644 new mode 100755 diff --git a/man/get_software_version.Rd b/man/get_software_version.Rd old mode 100644 new mode 100755 diff --git a/tests/testthat/test-endpoints.R b/tests/testthat/test-endpoints.R index cc47779..d3661d1 100755 --- a/tests/testthat/test-endpoints.R +++ b/tests/testthat/test-endpoints.R @@ -89,4 +89,11 @@ test_that("Testing if the `Ensembl API` functions work correctly", { expect_error(get_xrefs_by_name("homo_sapiens"), "Both 'species' and 'name' parameters are required") }) + ## test `get` + id <- "ENSGT00390000003602" + response <- get(res = "/cafe/genetree/id/{id}", id = id, + .headers = req_headers(content_type = "application/json") + ) + expect_equal(response[[1]]$status_code, 200) + }) From 2997a3a7a30a7bbdb642843353e4f1ca1a9c989e Mon Sep 17 00:00:00 2001 From: danymukesha Date: Wed, 4 Dec 2024 19:54:09 +0100 Subject: [PATCH 25/28] start adding and documenting the optional parameters to the endpoints funtions; started with `get_cafe_genetree_by_id` --- R/ensembl-endpoints.R | 37 +++++++++++++++++++++++++++++++--- man/get_cafe_genetree_by_id.Rd | 21 +++++++++++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/R/ensembl-endpoints.R b/R/ensembl-endpoints.R index 22e006b..c93f4a2 100755 --- a/R/ensembl-endpoints.R +++ b/R/ensembl-endpoints.R @@ -10,6 +10,18 @@ #' Retrieves a cafe tree of the gene tree using the gene tree stable identifier #' #' @param id A string representing the gene tree stable identifier. +#' @param callback String \emph{(optional)} Name of the callback subroutine +#' to be returned by the requested JSONP response. Required ONLY when using +#' JSONP as the serialisation method. Please +#' see also [the user guide](http://github.com/Ensembl/ensembl-rest/wiki). +#' @param compara String \emph{(optional)} Name of the compara database to use. +#' Multiple comparas exist on a server for separate species divisions. +#' Default is "vertebrates". +#' @param nh_format String \emph{(optional)} The format of a NH (New Hampshire) +#' request. Available only with the default setting to allow us to return +#' the cafe tree with Taxa names appended with number of members +#' and the p_value. Example: "homo_sapiens_3_0.123" where 3 is the number +#' of members and 0.123 is the p value. #' #' @return A list of parsed JSON responses containing the cafe tree #' for the provided gene tree stable identifier. @@ -22,13 +34,32 @@ #' @export #' @examples #' get_cafe_genetree_by_id("ENSGT00390000003602") -#' -get_cafe_genetree_by_id <- function(id) { +#' get_cafe_genetree_by_id("ENSGT00390000003602", +#' callback = "randomlygeneratedname") +#' get_cafe_genetree_by_id("ENSGT00390000003602", +#' compara = "vertebrates") +#' get_cafe_genetree_by_id("ENSGT00390000003602", +#' nh_format = "homo_sapiens_3_0.123") +#' +get_cafe_genetree_by_id <- function(id, callback = NULL, + compara = "vertebrates", + nh_format = NULL) { if (missing(id)) { stop("The 'id' parameter is required.") } + params <- list() + if (!is.null(callback)) { + params$callback <- callback + } + if (!is.null(compara)) { + params$compara <- compara + } + if (!is.null(nh_format)) { + params$nh_format <- nh_format + } response <- get(res = "/cafe/genetree/id/{id}", id = id, - .headers = req_headers(content_type = "application/json") + .headers = req_headers(content_type = "application/json"), + .params = params ) } diff --git a/man/get_cafe_genetree_by_id.Rd b/man/get_cafe_genetree_by_id.Rd index 3f51303..5725866 100755 --- a/man/get_cafe_genetree_by_id.Rd +++ b/man/get_cafe_genetree_by_id.Rd @@ -8,6 +8,21 @@ get_cafe_genetree_by_id(id) } \arguments{ \item{id}{A string representing the gene tree stable identifier.} + +\item{callback}{String \emph{(optional)} Name of the callback subroutine +to be returned by the requested JSONP response. Required ONLY when using +JSONP as the serialisation method. Please +see also \href{http://github.com/Ensembl/ensembl-rest/wiki}{the user guide}.} + +\item{compara}{String \emph{(optional)} Name of the compara database to use. +Multiple comparas exist on a server for separate species divisions. +Default is "vertebrates".} + +\item{nh_format}{String \emph{(optional)} The format of a NH (New Hampshire) +request. Available only with the default setting to allow us to return +the cafe tree with Taxa names appended with number of members +and the p_value. Example: "homo_sapiens_3_0.123" where 3 is the number +of members and 0.123 is the p value.} } \value{ A list of parsed JSON responses containing the cafe tree @@ -23,5 +38,11 @@ from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. } \examples{ get_cafe_genetree_by_id("ENSGT00390000003602") +get_cafe_genetree_by_id("ENSGT00390000003602", + callback = "randomlygeneratedname") +get_cafe_genetree_by_id("ENSGT00390000003602", + compara = "vertebrates") +get_cafe_genetree_by_id("ENSGT00390000003602", + nh_format = "homo_sapiens_3_0.123") } From 84e8c08006976a0b3baae66bf13ad4aaa5e2badc Mon Sep 17 00:00:00 2001 From: danymukesha Date: Tue, 24 Dec 2024 20:26:43 +0100 Subject: [PATCH 26/28] add endpoints from `Information`, here is the original list: https://rest.ensembl.org/ --- NAMESPACE | 26 + R/ensembl-endpoints.R | 1170 +++++++++++++++++++++++- R/get.R | 77 +- man/dot-_get_divisions.Rd | 25 + man/dot-_get_rest_version.Rd | 26 + man/dot-_get_software_version.Rd | 25 + man/dot-_get_variation_sources.Rd | 35 + man/get.Rd | 4 +- man/get_analysis_info.Rd | 30 + man/get_assembly_info.Rd | 45 + man/get_biotypes.Rd | 30 + man/get_biotypes_by_name.Rd | 34 + man/get_biotypes_groups.Rd | 39 + man/get_cafe_genetree_by_id.Rd | 7 +- man/get_cafe_genetree_by_species_id.Rd | 9 +- man/get_cafe_genetree_by_symbol.Rd | 3 +- man/get_compara_methods.Rd | 38 + man/get_compara_species_sets.Rd | 34 + man/get_comparas.Rd | 27 + man/get_consequence_types.Rd | 28 + man/get_data.Rd | 24 + man/get_eg_version.Rd | 24 + man/get_external_dbs.Rd | 40 + man/get_genetree_by_id.Rd | 3 +- man/get_genome_info.Rd | 34 + man/get_genome_info_by_accession.Rd | 34 + man/get_genome_info_by_assembly.Rd | 36 + man/get_genome_info_by_division.Rd | 35 + man/get_genome_info_by_taxonomy.Rd | 35 + man/get_population_individuals.Rd | 38 + man/get_region_info.Rd | 45 + man/get_species_info.Rd | 39 + man/get_species_populations.Rd | 39 + man/ping_service.Rd | 26 + 34 files changed, 2085 insertions(+), 79 deletions(-) create mode 100755 man/dot-_get_divisions.Rd create mode 100755 man/dot-_get_rest_version.Rd create mode 100755 man/dot-_get_software_version.Rd create mode 100755 man/dot-_get_variation_sources.Rd create mode 100755 man/get_analysis_info.Rd create mode 100755 man/get_assembly_info.Rd create mode 100755 man/get_biotypes.Rd create mode 100755 man/get_biotypes_by_name.Rd create mode 100755 man/get_biotypes_groups.Rd create mode 100755 man/get_compara_methods.Rd create mode 100755 man/get_compara_species_sets.Rd create mode 100755 man/get_comparas.Rd create mode 100755 man/get_consequence_types.Rd create mode 100755 man/get_data.Rd create mode 100755 man/get_eg_version.Rd create mode 100755 man/get_external_dbs.Rd create mode 100755 man/get_genome_info.Rd create mode 100755 man/get_genome_info_by_accession.Rd create mode 100755 man/get_genome_info_by_assembly.Rd create mode 100755 man/get_genome_info_by_division.Rd create mode 100755 man/get_genome_info_by_taxonomy.Rd create mode 100755 man/get_population_individuals.Rd create mode 100755 man/get_region_info.Rd create mode 100755 man/get_species_info.Rd create mode 100755 man/get_species_populations.Rd create mode 100755 man/ping_service.Rd diff --git a/NAMESPACE b/NAMESPACE index 422732a..2229fea 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,21 +1,42 @@ # Generated by roxygen2: do not edit by hand export("%>%") +export(._get_divisions) +export(._get_rest_version) +export(._get_software_version) +export(._get_variation_sources) export(genomic_range) export(get_alignment_by_region) export(get_analyses) +export(get_analysis_info) export(get_assemblies) +export(get_assembly_info) +export(get_biotypes) +export(get_biotypes_by_name) +export(get_biotypes_groups) export(get_cafe_genetree_by_id) export(get_cafe_genetree_by_species_id) export(get_cafe_genetree_by_symbol) +export(get_compara_methods) +export(get_compara_species_sets) +export(get_comparas) +export(get_consequence_types) export(get_cytogenetic_bands) +export(get_data) export(get_data_version2) export(get_data_versions) export(get_divisions) +export(get_eg_version) export(get_ensembl_genomes_version) +export(get_external_dbs) export(get_genetree_by_id) export(get_genetree_by_species_id) export(get_genetree_by_symbol) +export(get_genome_info) +export(get_genome_info_by_accession) +export(get_genome_info_by_assembly) +export(get_genome_info_by_division) +export(get_genome_info_by_taxonomy) export(get_homology_by_species_id) export(get_homology_by_symbol) export(get_id) @@ -25,12 +46,16 @@ export(get_ld_variants_by_pair) export(get_ld_variants_by_pair_combn) export(get_ld_variants_by_range) export(get_ld_variants_by_window) +export(get_population_individuals) export(get_populations) +export(get_region_info) export(get_rest_version) export(get_rest_version2) export(get_software_version) export(get_software_version2) export(get_species) +export(get_species_info) +export(get_species_populations) export(get_toplevel_sequence_info) export(get_toplevel_sequences) export(get_variant_consequences) @@ -43,6 +68,7 @@ export(get_xrefs_by_id) export(get_xrefs_by_name) export(get_xrefs_by_symbol) export(is_ensembl_reachable) +export(ping_service) importFrom(magrittr,"%>%") importFrom(rlang,.data) importFrom(tibble,tibble) diff --git a/R/ensembl-endpoints.R b/R/ensembl-endpoints.R index c93f4a2..53a7e63 100755 --- a/R/ensembl-endpoints.R +++ b/R/ensembl-endpoints.R @@ -41,26 +41,29 @@ #' get_cafe_genetree_by_id("ENSGT00390000003602", #' nh_format = "homo_sapiens_3_0.123") #' -get_cafe_genetree_by_id <- function(id, callback = NULL, +get_cafe_genetree_by_id <- function(id, callback = "myrandomfunctionname", compara = "vertebrates", - nh_format = NULL) { + nh_format = "simple") { if (missing(id)) { stop("The 'id' parameter is required.") } - params <- list() + + cat("\n`compara` seems to not be working for this endpoint. + Hence this specific parameter is ignored for the moment. + Here is more detail on the paramater: + https://rest.ensembl.org/documentation/info/cafe_tree + \n") + if (!is.null(callback)) { - params$callback <- callback - } - if (!is.null(compara)) { - params$compara <- compara - } - if (!is.null(nh_format)) { - params$nh_format <- nh_format + response <- get(res = "cafe/genetree/id/{id}", id = id, + nh_format = nh_format, + .headers = req_headers(content_type = "application/json")) + } else { + warning("Callback is null. Returning an empty response.") + response <- list() } - response <- get(res = "/cafe/genetree/id/{id}", id = id, - .headers = req_headers(content_type = "application/json"), - .params = params - ) + + response } #' Get cafe gene tree by symbol @@ -68,8 +71,7 @@ get_cafe_genetree_by_id <- function(id, callback = NULL, #' Retrieves the cafe tree of the gene tree that contains the gene identified #' by a symbol #' -#' @param species A string representing the species name (e.g., -#' "homo_sapiens"). +#' @param species A string representing the species name (e.g., "homo_sapiens"). #' @param symbol A string representing the gene symbol (e.g., "BRCA2"). #' #' @return A list of parsed JSON responses containing the cafe tree @@ -91,16 +93,21 @@ get_cafe_genetree_by_symbol <- function(species, symbol) { species = species, symbol = symbol, symbol = symbol, .headers = req_headers(content_type = "application/json") ) + + response } #' Get cafe gene tree by species id #' -#' Retrieves the cafe tree of the gene tree that contains the gene/transcript/translation stable identifier in the given species +#' Retrieves the cafe tree of the gene tree that contains the +#' gene/transcript/translation stable identifier in the given species #' #' @param species A string representing the species name (e.g., "homo_sapiens"). -#' @param id A string representing the gene, transcript, or translation stable identifier. +#' @param id A string representing the gene, transcript, or translation +#' stable identifier. #' -#' @return A list of parsed JSON responses containing the cafe tree for the provided species and stable identifier. +#' @return A list of parsed JSON responses containing the cafe tree for +#' the provided species and stable identifier. #' #' @note #' See more about the implemented endpoint [get_cafe_genetree_by_species_id()] @@ -118,6 +125,7 @@ get_cafe_genetree_by_species_id <- function(species, id) { species = species, id = id, .headers = req_headers(content_type = "application/json") ) + response } #' Get gene tree by id @@ -126,7 +134,8 @@ get_cafe_genetree_by_species_id <- function(species, id) { #' #' @param id A string representing the gene tree stable identifier. #' -#' @return A list of parsed JSON responses containing the gene tree for the provided gene tree stable identifier. +#' @return A list of parsed JSON responses containing the gene tree for +#' the provided gene tree stable identifier. #' #' @note #' See more about the implemented endpoint [get_genetree_by_id()] @@ -380,6 +389,1127 @@ get_xrefs_by_name <- function(species, name) { # -------------------------------------------------------- # ## Information ==== +#' Get the names of analyses involved in generating Ensembl data +#' +#' Retrieves a list of analysis names associated with generating Ensembl +#' data for a given species. +#' +#' @param species A string representing the species name or alias +#' (e.g., "homo_sapiens"). +#' @param callback (Optional) A string representing the name of the callback +#' subroutine for JSONP responses. +#' +#' @return A list of analysis names related to the specified species. +#' +#' See more about the implemented endpoint [get_analysis_info()] +#' on the following [GET info/analysis/:species](https://rest.ensembl.org/documentation/info/analysis) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_analysis_info("homo_sapiens") +#' get_analysis_info("homo_sapiens", callback = "randomlygeneratedname") +get_analysis_info <- function(species, callback = "randomlygeneratedname") { + if (missing(species)) { + stop("'species' parameter is required.") + } + if (!is.null(callback)) { + response <- get(res = "/info/analysis/{species}", species = species, + .headers = req_headers(content_type = "application/json"), callback) + } else { + response <- get(res = "/info/analysis/{species}", species = species, + .headers = req_headers(content_type = "application/json")) + } + + response +} + +#' Get the available assemblies for a species +#' +#' Retrieves a list of available assemblies for a given species, +#' including toplevel sequences, chromosomes, and optionally cytogenetic +#' bands and synonyms. +#' +#' @param species A string representing the species name or alias +#' (e.g., "homo_sapiens"). +#' @param bands (Optional) A boolean (0 or 1) indicating whether to +#' include karyotype band information. Default is 0. +#' @param synonyms (Optional) A boolean (0 or 1) indicating whether to +#' include information about known synonyms. Default is 0. +#' @param callback (Optional) A string representing the name of the callback +#' subroutine for JSONP responses. +#' +#' @return A list of parsed JSON responses containing information about +#' the available assemblies for the specified species. +#' +#' See more about the implemented endpoint [get_assembly_info()] +#' on the following [GET info/assembly/:species](https://rest.ensembl.org/documentation/info/assembly_info) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_assembly_info("homo_sapiens") +#' get_assembly_info("homo_sapiens", bands = 1) +#' get_assembly_info("homo_sapiens", synonyms = 1, +#' callback = "randomlygeneratedname") +get_assembly_info <- function(species, bands = 0, synonyms = 0, + callback = "randomlygeneratedname") { + if (missing(species)) { + stop("'species' parameter is required.") + } + + if (!is.null(callback)) { + response <- get(res = "/info/assembly/{species}", species = species, + bands = bands, synonyms = synonyms, + .headers = req_headers(content_type = "application/json"), + .params = params) + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get information about a specific toplevel sequence region for a species +#' +#' Retrieves information about the specified toplevel sequence region for +#' a given species, with optional details on karyotype bands and synonyms. +#' +#' @param species A string representing the species name or alias (e.g., "homo_sapiens"). +#' @param region_name A string representing the name of the toplevel sequence region (e.g., "X"). +#' @param bands (Optional) A boolean (0 or 1) indicating whether to include +#' karyotype band information. Default is 0. +#' @param synonyms (Optional) A boolean (0 or 1) indicating whether to include +#' information about known synonyms. Default is 0. +#' @param callback (Optional) A string representing the name of the callback +#' subroutine for JSONP responses. +#' +#' @return A list of parsed JSON responses containing information about +#' the specified sequence region for the given species. +#' +#' See more about the implemented endpoint [get_region_info()] +#' on the following [GET info/assembly/:species/:region_name](https://rest.ensembl.org/documentation/info/assembly_stats) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_region_info("homo_sapiens", "X") +#' get_region_info("homo_sapiens", "X", bands = 1) +#' get_region_info("homo_sapiens", "X", synonyms = 1, callback = "randomlygeneratedname") +get_region_info <- function(species, region_name, bands = 0, synonyms = 0, + callback = "randomlygeneratedname") { + if (missing(species) || missing(region_name)) { + stop("'species' and 'region_name' parameters are required.") + } + + if (!is.null(callback)) { + response <- get( + res = "/info/assembly/{species}/{region_name}", + species = species, region_name = region_name, + bands = bands, synonyms = synonyms, + .headers = req_headers(content_type = "application/json")) + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get the functional classifications of gene models for a species +#' +#' Retrieves the list of functional classifications (biotypes) of gene models +#' that Ensembl associates with a particular species. +#' Useful for restricting the type of genes/transcripts retrieved by other endpoints. +#' +#' @param species A string representing the species name or alias (e.g., "homo_sapiens"). +#' @param callback (Optional) A string representing the name of the callback subroutine +#' for JSONP responses. +#' +#' @return A list of parsed JSON responses containing the biotypes for the specified species. +#' +#' See more about the implemented endpoint [get_biotypes()] +#' on the following [GET info/biotypes/:species](https://rest.ensembl.org/documentation/info/biotypes) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_biotypes("homo_sapiens") +#' get_biotypes("homo_sapiens", callback = "randomlygeneratedname") +get_biotypes <- function(species, callback = "randomlygeneratedname") { + if (missing(species)) { + stop("'species' parameter is required.") + } + + if (!is.null(callback)) { + response <- get( + res = "/info/biotypes/{species}", species = species, + .headers = req_headers(content_type = "application/json")) + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get properties of biotypes within a group +#' +#' Retrieves a list of available biotype groups or, if a group is specified, +#' the properties of biotypes within that group. +#' Optionally, the object type (gene or transcript) can be used to filter the results. +#' +#' @param group (Optional) A string representing the biotype group (e.g., "coding"). +#' If not provided, the available biotype groups are returned. +#' @param object_type (Optional) A string specifying the object type ("gene" or "transcript"). +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' +#' @return A list of parsed JSON responses containing the properties of biotypes within +#' the specified group or all biotype groups if no group is provided. +#' +#' See more about the implemented endpoint [get_biotypes_groups()] +#' on the following [GET info/biotypes/groups/:group/:object_type](https://rest.ensembl.org/documentation/info/biotypes_groups) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_biotypes_groups() +#' get_biotypes_groups(group = "coding") +#' get_biotypes_groups(group = "coding", object_type = "gene") +#' get_biotypes_groups(group = "coding", object_type = "gene", callback = "randomlygeneratedname") +get_biotypes_groups <- function(group = '', object_type = '', + callback = "randomlygeneratedname") { + # TODO: Create an issue: + # To handle the case in which `group` parameter is null or empty + # while `object_type` is not null nor empty. + + if (!is.null(callback)) { + query_params <- list() + if (!is.null(group)) query_params$group <- group + if (!is.null(object_type)) query_params$object_type <- object_type + if (!is.null(callback)) query_params$callback <- callback + + headers <- req_headers(content_type = "application/json") + + response <- + do.call(get, + c(list( + res = "/info/biotypes/groups/{group}/{object_type}", + .headers = headers), + query_params) + ) + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get properties of biotypes by name +#' +#' Retrieves the properties of biotypes with a given name. Optionally, the object type (gene or transcript) can be provided for filtering. +#' +#' @param name A string representing the biotype name (e.g., "protein_coding"). +#' @param object_type (Optional) A string specifying the object type ("gene" or "transcript"). +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' +#' @return A list of parsed JSON responses containing the properties of biotypes with the given name. +#' +#' See more about the implemented endpoint [get_biotypes_by_name()] +#' on the following [GET info/biotypes/name/:name/:object_type](https://rest.ensembl.org/documentation/info/biotypes_name) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_biotypes_by_name("protein_coding") +#' get_biotypes_by_name("protein_coding", object_type = "gene") +#' get_biotypes_by_name("protein_coding", object_type = "gene", callback = "randomlygeneratedname") +get_biotypes_by_name <- function(name, object_type = "", + callback = "randomlygeneratedname") { + if (missing(name)) { + stop("'name' parameter is required.") + } + + if (!is.null(callback)) { + query_params <- list() + if (!is.null(name)) query_params$name <- name + if (!is.null(object_type)) query_params$object_type <- object_type + if (!is.null(callback)) query_params$callback <- callback + + headers <- req_headers(content_type = "application/json") + + response <- + do.call(get, + c(list( + res = "/info/compara/species_sets/{name}/{object_type}", + .headers = headers), + query_params) + ) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get list of compara methods +#' +#' Retrieves a list of all compara analyses available (an analysis defines the type +#' of comparative data). Optional filtering by class or compara database can be applied. +#' +#' @param callback (Optional) A string representing the name of the callback subroutine +#' for JSONP responses. +#' @param class (Optional) A string specifying the class of the method to query for. +#' Regular expression patterns are supported (e.g., "GenomicAlign"). +#' @param compara (Optional) A string representing the name of the compara database +#' to use (e.g., "vertebrates"). +#' +#' @return A list of parsed JSON responses containing all available compara methods. +#' +#' See more about the implemented endpoint [get_compara_methods()] +#' on the following [GET info/compara/methods](https://rest.ensembl.org/documentation/info/compara_methods) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_compara_methods() +#' get_compara_methods(class = "GenomicAlign") +#' get_compara_methods(compara = "vertebrates", class = "GenomicAlign") +get_compara_methods <- function(callback = "randomlygeneratedname", + class = NULL, compara = NULL) { + + if (!is.null(callback)) { + url <- "/info/compara/methods" + query_params <- list() + if (!is.null(class)) query_params$class <- class + if (!is.null(compara)) query_params$compara <- compara + if (!is.null(callback)) query_params$callback <- callback + + headers <- req_headers(content_type = "application/json") + + response <- do.call(get, c(list(res = url, .headers = headers), query_params)) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + return(response) +} + +#' Get collections of species analysed with a specified compara method +#' +#' Retrieves a list of all collections of species analysed with the specified compara method. +#' The compara method must be one of the methods returned by the `/info/compara/methods` endpoint. +#' +#' @param method A string representing the compara method to filter by (e.g., "EPO"). +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' @param compara (Optional) A string representing the name of the compara database to use (e.g., "vertebrates"). +#' +#' @return A list of parsed JSON responses containing all collections of species analysed with the specified compara method. +#' +#' See more about the implemented endpoint [get_compara_species_sets()] +#' on the following [GET info/compara/species_sets/:method](https://rest.ensembl.org/documentation/info/compara_species_sets) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_compara_species_sets("EPO") +#' get_compara_species_sets("EPO", compara = "vertebrates") +get_compara_species_sets <- function(method, callback = "randomlygeneratedname", + compara = NULL) { + if (missing(method)) { + stop("'method' parameter is required.") + } + + if (!is.null(callback)) { + query_params <- list() + if (!is.null(method)) query_params$method <- method + if (!is.null(compara)) query_params$compara <- compara + if (!is.null(callback)) query_params$callback <- callback + + headers <- req_headers(content_type = "application/json") + + response <- do.call(get, + c(list( + res = "/info/compara/species_sets/{method}", + .headers = headers), + query_params) + ) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + response +} + +#' Get a list of all available comparative genomics databases and their data release +#' +#' Retrieves a list of all available comparative genomics databases and their data release. +#' This endpoint is deprecated, and users are advised to use the `/info/genomes/division` endpoint instead. +#' +#' @param callback (Optional) A string representing the name of the callback subroutine +#' for JSONP responses. +#' +#' @return A list of parsed JSON responses containing all available comparative genomics +#' databases and their data release. +#' +#' See more about the implemented endpoint [get_comparas()] +#' on the following [GET info/comparas](https://rest.ensembl.org/documentation/info/comparas) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_comparas() +get_comparas <- function(callback = "randomlygeneratedname") { + if (!is.null(callback)) { + response <- get( + res = "/info/comparas", + callback = callback, + .headers = req_headers(content_type = "application/json") + ) + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get a list of available data releases on the Ensembl REST server +#' +#' Retrieves a list of the data releases available on the Ensembl REST server. It may return more than one release if the server has an unfrequent, non-standard configuration. +#' +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' +#' @return A list of parsed JSON responses containing the available data releases on the Ensembl REST server. +#' +#' See more about the implemented endpoint [get_data()] +#' on the following [GET info/data](https://rest.ensembl.org/documentation/info/data) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_data() +get_data <- function(callback = "randomlygeneratedname") { + if (!is.null(callback)) { + response <- get( + res = "/info/data", + callback = callback, + .headers = req_headers(content_type = "application/json") + ) + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get the Ensembl Genomes version of the databases backing the service +#' +#' Retrieves the Ensembl Genomes version of the databases supporting the current service. +#' +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' +#' @return A parsed JSON response containing the Ensembl Genomes version of the databases. +#' +#' See more about the implemented endpoint [get_eg_version()] +#' on the following [GET info/eg_version](https://rest.ensembl.org/documentation/info/eg_version) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_eg_version() +get_eg_version <- function(callback = "randomlygeneratedname") { + if (!is.null(callback)) { + response <- get( + res = "/info/eg_version", + callback = callback, + .headers = req_headers(content_type = "application/json") + ) + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get external databases for a species +#' +#' Retrieves a list of all available external sources for a given species. +#' +#' @param species A string representing the species name or alias (e.g., "homo_sapiens"). +#' @param callback (Optional) A string representing the name of the callback subroutine +#' for JSONP responses. +#' @param feature (Optional) A string representing the feature to filter external DB entries +#' (e.g., "dna_align_feature", "protein_align_feature", "unmapped_object", "xref", "seq_region_synonym"). +#' @param filter (Optional) A string to restrict external DB searches to a single source +#' or pattern (e.g., "HGNC", "GO%"). +#' +#' @return A parsed JSON response containing a list of external sources associated +#' with the given species. +#' +#' See more about the implemented endpoint [get_external_dbs()] +#' on the following [GET info/external_dbs/:species](https://rest.ensembl.org/documentation/info/external_dbs) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_external_dbs("homo_sapiens") +#' get_external_dbs("homo_sapiens", feature = "xref", filter = "HGNC") +get_external_dbs <- function(species, callback = "randomlygeneratedname", + feature = NULL, filter = NULL) { + if (missing(species)) { + stop("'species' parameter is required.") + } + + if (!is.null(callback)) { + query_params <- list() + if (!is.null(species)) query_params$species <- species + if (!is.null(feature)) query_params$feature <- feature + if (!is.null(filter)) query_params$filter <- filter + if (!is.null(callback)) query_params$callback <- callback + + headers <- req_headers(content_type = "application/json") + + response <- do.call(get, + c(list( + res = "/info/external_dbs/{species}", + .headers = headers), + query_params)) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get list of all Ensembl divisions +#' +#' Retrieves a list of all available Ensembl divisions for which information is accessible. +#' +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' +#' @return A parsed JSON response containing the list of Ensembl divisions. +#' +#' See more about the implemented endpoint [._get_divisions()] +#' on the following [GET info/divisions](https://rest.ensembl.org/documentation/info/info_divisions) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' ._get_divisions() +#' ._get_divisions(callback = "randomlygeneratedname") +._get_divisions <- function(callback = "randomlygeneratedname") { + + if (!is.null(callback)) { + response <- get( + res = "/info/divisions", + callback = callback, + .headers = req_headers(content_type = "application/json") + ) + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get genome information +#' +#' Retrieves detailed information about a given genome based on its production name. +#' +#' @param name (Required) A string representing the production name of the genome +#' (e.g., "arabidopsis_thaliana"). +#' @param callback (Optional) A string representing the name of the callback subroutine +#' for JSONP responses. +#' @param expand (Optional) A boolean value (0 or 1). If set to 1, expands +#' the information to include details of sequences (can be very large). +#' Default is NULL. +#' +#' @return A parsed JSON response containing information about the specified genome. +#' +#' See more about the implemented endpoint [get_genome_info()] +#' on the following [GET info/genomes/:genome_name](https://rest.ensembl.org/documentation/info/info_genome) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_genome_info(name = "arabidopsis_thaliana") +#' get_genome_info(name = "arabidopsis_thaliana", expand = 1) +#' get_genome_info(name = "arabidopsis_thaliana", callback = "randomlygeneratedname") +get_genome_info <- function(name, callback = "randomlygeneratedname", + expand = NULL) { + if (missing(name)) { + stop("The 'name' parameter is required.") + } + + if (!is.null(callback)) { + query_params <- list() + if (!is.null(name)) query_params$name <- name + if (!is.null(callback)) query_params$callback <- callback + if (!is.null(expand)) query_params$expand <- expand + + headers <- req_headers(content_type = "application/json") + + response <- do.call(get, + c(list( + res = "/info/genomes/{name}", + .headers = headers), + query_params)) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get genome information by INSDC accession +#' +#' Retrieves detailed information about genomes containing a specified INSDC accession. +#' +#' @param accession (Required) A string representing the INSDC sequence accession (optionally versioned), e.g., "U00096". +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' @param expand (Optional) A boolean value (0 or 1). If set to 1, expands the information to include details of sequences (can be very large). +#' +#' @return A parsed JSON response containing information about genomes with the specified INSDC accession. +#' +#' See more about the implemented endpoint [get_genome_info_by_accession()] +#' on the following [GET info/genomes/accession/:accession](https://rest.ensembl.org/documentation/info/info_genomes_accession) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_genome_info_by_accession(accession = "U00096") +#' get_genome_info_by_accession(accession = "U00096", expand = 1) +#' get_genome_info_by_accession(accession = "U00096", callback = "randomlygeneratedname") +get_genome_info_by_accession <- function(accession, callback = "randomlygeneratedname", + expand = NULL) { + if (missing(accession)) { + stop("The 'accession' parameter is required.") + } + + if (!is.null(callback)) { + query_params <- list() + if (!is.null(accession)) query_params$accession <- accession + if (!is.null(callback)) query_params$callback <- callback + if (!is.null(expand)) query_params$expand <- expand + + headers <- req_headers(content_type = "application/json") + + response <- do.call(get, + c(list( + res = "/info/genomes/accession/{accession}", + .headers = headers), + query_params)) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get genome information by assembly ID +#' +#' Retrieves information about a genome associated with a specified assembly ID. +#' +#' @param assembly_id (Required) A string representing the INSDC assembly ID (optionally versioned, e.g., "GCA_902167145.1"). +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' @param expand (Optional) A boolean value (0 or 1). If set to 1, expands the information +#' to include details of sequences (can be very large). +#' +#' @return A parsed JSON response containing information about the genome associated +#' with the specified assembly ID. +#' +#' See more about the implemented endpoint [get_genomes_by_assembly()] +#' on the following [GET info/genomes/assembly/:assembly_id](https://rest.ensembl.org/documentation/info/info_genomes_assembly) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_genome_info_by_assembly(assembly_id = "GCA_902167145.1") +#' get_genome_info_by_assembly(assembly_id = "GCA_902167145.1", expand = 1) +#' get_genome_info_by_assembly(assembly_id = "GCA_902167145.1", callback = "randomlygeneratedname") +get_genome_info_by_assembly <- function(assembly_id, callback = "randomlygeneratedname", + expand = NULL) { + if (missing(assembly_id)) { + stop("The 'assembly_id' parameter is required.") + } + + if (!is.null(callback)) { + query_params <- list() + if (!is.null(assembly_id)) query_params$assembly_id <- assembly_id + if (!is.null(callback)) query_params$callback <- callback + if (!is.null(expand)) query_params$expand <- expand + + headers <- req_headers(content_type = "application/json") + + response <- do.call(get, + c(list( + res = "/info/genomes/assembly/{assembly_id}", + .headers = headers), + query_params)) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get genome information for a specific division +#' +#' Retrieves information about all genomes in a given division. +#' Note: The response may be very large for divisions like Ensembl Bacteria. +#' +#' @param division_name (Required) A string representing the name of the division (e.g., "EnsemblPlants"). +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' @param expand (Optional) A boolean value (0 or 1). If set to 1, expands the information to include details of sequences (can be very large). +#' +#' @return A parsed JSON response containing information about genomes in the specified division. +#' +#' See more about the implemented endpoint [get_genomes_by_division()] +#' on the following [GET info/genomes/division/:division_name](https://rest.ensembl.org/documentation/info/info_genomes_division) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_genome_info_by_division(division_name = "EnsemblPlants") +#' get_genome_info_by_division(division_name = "EnsemblPlants", expand = 1) +#' get_genome_info_by_division(division_name = "EnsemblPlants", callback = "randomlygeneratedname") +get_genome_info_by_division <- function(division_name, callback = "randomlygeneratedname", + expand = NULL) { + if (missing(division_name)) { + stop("The 'division_name' parameter is required.") + } + + if (!is.null(callback)) { + query_params <- list() + if (!is.null(division_name)) query_params$division_name <- division_name + if (!is.null(callback)) query_params$callback <- callback + if (!is.null(expand)) query_params$expand <- expand + + headers <- req_headers(content_type = "application/json") + + response <- do.call(get, + c(list( + res = "/info/genomes/division/{division_name}", + .headers = headers), + query_params)) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get genome information by taxonomy node +#' +#' Retrieves information about all genomes beneath a given node of the taxonomy. +#' +#' @param taxon_name (Required) A string representing the taxon name or NCBI taxonomy ID (e.g., "Homo sapiens"). +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' @param expand (Optional) A boolean value (0 or 1). If set to 1, expands the information +#' to include details of sequences (can be very large). +#' +#' @return A parsed JSON response containing information about genomes beneath the specified taxonomy node. +#' +#' See more about the implemented endpoint [get_genomes_by_taxonomy()] +#' on the following [GET info/genomes/taxonomy/:taxon_name](https://rest.ensembl.org/documentation/info/info_genomes_taxonomy) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_genome_info_by_taxonomy(taxon_name = "Homo sapiens") +#' get_genome_info_by_taxonomy(taxon_name = "Homo sapiens", expand = 1) +#' get_genome_info_by_taxonomy(taxon_name = "Homo sapiens", callback = "randomlygeneratedname") +get_genome_info_by_taxonomy <- function(taxon_name, callback = "randomlygeneratedname", + expand = NULL) { + if (missing(taxon_name)) { + stop("The 'taxon_name' parameter is required.") + } + + if (!is.null(callback)) { + query_params <- list() + if (!is.null(taxon_name)) query_params$taxon_name <- gsub(" ", "%20", taxon_name) + if (!is.null(callback)) query_params$callback <- callback + if (!is.null(expand)) query_params$expand <- expand + + headers <- req_headers(content_type = "application/json") + + response <- do.call(get, + c(list( + res = "/info/genomes/taxonomy/{taxon_name}", + .headers = headers), + query_params)) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Check Service Status +#' +#' Sends a ping request to the server to check if the service is alive. +#' +#' @param callback (Optional) A string representing the name of the callback +#' subroutine for JSONP responses. +#' +#' @return A parsed JSON response indicating the status of the service. +#' +#' See more about the implemented endpoint [ping_service()] +#' on the following [GET info/ping](https://rest.ensembl.org/documentation/info/ping) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' ping_service() +#' ping_service(callback = "randomlygeneratedname") +ping_service <- function(callback = "randomlygeneratedname") { + if (!is.null(callback)) { + response <- get( + res = "/info/ping", + callback = callback, + .headers = req_headers(content_type = "application/json") + ) + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get REST API Version +#' +#' Retrieves the current version of the Ensembl REST API. +#' +#' @param callback (Optional) A string representing the name of the callback +#' subroutine for JSONP responses. +#' +#' @return A parsed JSON response containing the REST API version information. +#' +#' See more about the implemented endpoint [._get_rest_version()] +#' on the following [GET info/rest](https://rest.ensembl.org/documentation/info/rest) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' ._get_rest_version() +#' ._get_rest_version(callback = "randomlygeneratedname") +._get_rest_version <- function(callback = "randomlygeneratedname") { + + if (!is.null(callback)) { + response <- get( + res = "/info/rest", + callback = callback, + .headers = req_headers(content_type = "application/json") + ) + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get Software Version +#' +#' Retrieves the current version of the Ensembl API used by the REST server. +#' +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' +#' @return A parsed JSON response containing the Ensembl API version information. +#' +#' See more about the implemented endpoint [._get_software_version()] +#' on the following [GET info/software](https://rest.ensembl.org/documentation/info/software) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' ._get_software_version() +#' ._get_software_version(callback = "randomlygeneratedname") +._get_software_version <- function(callback = "randomlygeneratedname") { + if (!is.null(callback)) { + response <- get( + res = "/info/software", + callback = callback, + .headers = req_headers(content_type = "application/json") + ) + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get Species Information +#' +#' Retrieves a list of all available species, their aliases, available adaptor groups, and data release. +#' +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' @param division (Optional) A string to filter by Ensembl or Ensembl Genomes division (default is "EnsemblVertebrates"). +#' @param hide_strain_info (Optional) A boolean flag to show/hide strain and +#' strain_collection information (default is 0, which shows strain info). +#' @param strain_collection (Optional) A string to filter by strain collection (e.g., "mouse"). +#' +#' @return A parsed JSON response containing species information. +#' +#' See more about the implemented endpoint [get_species_info()] +#' on the following [GET info/species](https://rest.ensembl.org/documentation/info/species) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_species_info() +#' get_species_info(division = "EnsemblPlants") +#' get_species_info(hide_strain_info = 1) +#' get_species_info(strain_collection = "mouse") +get_species_info <- function(callback = "randomlygeneratedname", + division = "EnsemblVertebrates", + hide_strain_info = 0, strain_collection = NULL) { + + if (!is.null(callback)) { + query_params <- list() + if (!is.null(callback)) query_params$callback <- callback + if (!is.null(division)) query_params$division <- division + if (!is.null(hide_strain_info)) query_params$hide_strain_info <- hide_strain_info + if (!is.null(strain_collection)) query_params$strain_collection <- strain_collection + + headers <- req_headers(content_type = "application/json") + + response <- do.call(get, + c(list( + res = "/info/species", + .headers = headers), + query_params)) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get Variation Sources for a Species +#' +#' Retrieves the variation sources used in Ensembl for a given species. +#' +#' @param species (Required) A string representing the species name or alias (e.g., "homo_sapiens"). +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' @param filter (Optional) A string to restrict the variation source searches to a single source +#' (e.g., "dbSNP", "ClinVar", "OMIM", "UniProt", "HGMD"). +#' +#' @return A parsed JSON response containing the variation sources for the specified species. +#' +#' See more about the implemented endpoint [._get_variation_sources()] +#' on the following [GET info/variation/:species](https://rest.ensembl.org/documentation/info/variation) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' ._get_variation_sources("homo_sapiens") +#' ._get_variation_sources("homo_sapiens", filter = "ClinVar") +#' ._get_variation_sources("homo_sapiens", callback = "randomlygeneratedname") +._get_variation_sources <- function(species, callback = "randomlygeneratedname", + filter = NULL) { + if (missing(species)) { + stop("The 'species' parameter is required.") + } + + if (!is.null(callback)) { + query_params <- list() + if (!is.null(callback)) query_params$callback <- callback + if (!is.null(species)) query_params$species <- species + if (!is.null(filter)) query_params$filter <- filter + + headers <- req_headers(content_type = "application/json") + + response <- do.call(get, + c(list( + res = "/info/variation/{species}", + .headers = headers), + query_params)) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get Variant Consequence Types +#' +#' Retrieves a list of all variant consequence types available in Ensembl. +#' +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' @param rank (Optional) A boolean (0 or 1) to include consequence ranking in the response. Default is 0. +#' +#' @return A parsed JSON response containing the list of variant consequence types. +#' +#' See more about the implemented endpoint [get_consequence_types()] +#' on the following [GET info/variation/consequence_types](https://rest.ensembl.org/documentation/info/variation_consequence_types) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_consequence_types() +#' get_consequence_types(rank = 1) +#' get_consequence_types(callback = "randomCallback") +get_consequence_types <- function(callback = "randomlygeneratedname", + rank = NULL) { + + if (!is.null(callback)) { + query_params <- list() + if (!is.null(callback)) query_params$callback <- callback + if (!is.null(rank)) query_params$species <- rank + + headers <- req_headers(content_type = "application/json") + + response <- do.call(get, + c(list( + res = "/info/variation/consequence_types", + .headers = headers), + query_params)) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get Population Individuals +#' +#' Retrieves a list of all individuals for a specified population from a species in Ensembl. +#' +#' @param population_name (Required) A string representing the name of the population (e.g., "1000GENOMES:phase_3:ASW"). +#' @param species (Required) A string representing the species name or alias (e.g., "human"). +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' +#' @return A parsed JSON response containing the list of individuals for the specified population. +#' +#' See more about the implemented endpoint [get_population_individuals()] +#' on the following [GET info/variation/populations/:species/:population_name](https://rest.ensembl.org/documentation/info/variation_population_name) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_population_individuals(species = "human", population_name = "1000GENOMES:phase_3:ASW") +#' get_population_individuals(species = "homo_sapiens", population_name = "1000GENOMES:phase_3:YRI") +#' get_population_individuals( +#' species = "human", +#' population_name = "1000GENOMES:phase_3:CEU", +#' callback = "randomCallback" +#' ) +get_population_individuals <- function(species, population_name, + callback = "randomlygeneratedname") { + if (missing(species) || missing(population_name)) { + stop("Both 'species' and 'population_name' are required parameters.") + } + + if (!is.null(callback)) { + query_params <- list() + if (!is.null(species)) query_params$species <- species + if (!is.null(population_name)) query_params$population_name <- population_name + if (!is.null(callback)) query_params$callback <- callback + + headers <- req_headers(content_type = "application/json") + + response <- + do.call(get, + c(list( + res = "/info/variation/populations/{species}/{population_name}", + .headers = headers), + query_params) + ) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get Populations for a Species +#' +#' Retrieves a list of all populations for a specified species in Ensembl. +#' +#' @param species (Required) A string representing the species name or alias (e.g., "homo_sapiens"). +#' @param callback (Optional) A string representing the name of the callback subroutine for JSONP responses. +#' @param filter (Optional) A string to restrict populations returned +#' (e.g., "LD" to filter populations with linkage disequilibrium data). +#' +#' @return A parsed JSON response containing the list of populations for the specified species. +#' +#' See more about the implemented endpoint [get_species_populations()] +#' on the following [GET info/variation/populations/:species](https://rest.ensembl.org/documentation/info/variation_populations) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_species_populations(species = "homo_sapiens") +#' get_species_populations(species = "human", filter = "LD") +#' get_species_populations( +#' species = "homo_sapiens", +#' callback = "randomlygeneratedname", +#' filter = "LD" +#' ) +get_species_populations <- function(species, callback = "randomlygeneratedname", + filter = NULL) { + if (missing(species)) { + stop("'species' is a required parameter.") + } + + if (!is.null(callback)) { + query_params <- list() + if (!is.null(species)) query_params$species <- species + if (!is.null(filter)) query_params$filter <- filter + if (!is.null(callback)) query_params$callback <- callback + + headers <- req_headers(content_type = "application/json") + + response <- + do.call(get, + c(list( + res = "/info/variation/populations/{species}", + .headers = headers), + query_params)) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + + # -------------------------------------------------------- # ## Linkage Disequilibrium ==== diff --git a/R/get.R b/R/get.R index 75f7184..9b8618c 100755 --- a/R/get.R +++ b/R/get.R @@ -10,66 +10,41 @@ #' [req_headers()] to create such an object. #' @param rate The maximum number of requests per second to allow. #' Defaults to 15 per minute (15/60). +#' @param verbose Logical, if TRUE, enables detailed logging of request and response details. #' #' @return A list of responses, one for each request made. #' #' @keywords internal -get <- function(res, ..., .headers = req_headers(), rate = 15/60) { # for get the body could be optional? +get <- function(res, ..., .headers = req_headers(), rate = 15/60, verbose = FALSE) { requests <- reqs(res, ..., .headers = .headers) requests <- purrr::map(requests, httr2::req_throttle, rate = rate) - responses <- httr2::req_perform_parallel(requests) - httr2::throttle_status() - #checking the rate limit exceptions and add delay if needed - for (i in seq_along(responses)) { - status_code <- httr2::resp_status(responses[[i]]) # I am not sure whether the error will arrive here - if (status_code == 429) { - #the `Retry-After` in the response_headers will only show up once you exceed the rate limit - retry_after <- as.numeric(httr2::resp_headers(responses[[i]])$`Retry-After`) - message(glue::glue("Rate limit reached, waiting {retry_after} seconds before retrying...")) - Sys.sleep(retry_after) - responses[[i]] <- httr2::req_perform(requests[[i]]) - } else if (status_code != 200) { - warning(glue::glue("Request failed with status code {status_code}.")) - } - } - return(responses) -} - -#---------------------------------------------------------------------------------------------- -## example for the get, but for the user it will still require a bit more knowledge of the APIs -# response <- get("/archive/id/{id}", -# id = "ENSG00000139618", -# type = "genomic", -# species = "human") + responses <- vector("list", length(requests)) + for (i in seq_along(requests)) { + if (verbose) message(glue::glue("Performing request {i}/{length(requests)}...")) + repeat { + response <- httr2::req_perform(requests[[i]]) + status_code <- httr2::resp_status(response) -# Retrieve a given Ensembl stable ID, with a low level function -# https://rest.ensembl.org/documentation/info/archive_id_get -get_archive_id <- function(id, callback = NULL) { - if (missing(id)) { - stop("The 'id' parameter is required.") + if (status_code == 429) { + retry_after <- as.numeric(httr2::resp_headers(response)$`Retry-After`) + if (is.na(retry_after)) { + warning("Rate limit exceeded, but `Retry-After` header is missing. Defaulting to 60 seconds.") + retry_after <- 60 + } + message(glue::glue("Rate limit reached for request {i}, waiting {retry_after} seconds...")) + Sys.sleep(retry_after) + } else { + if (status_code != 200) { + warning(glue::glue("Request {i} failed with status code {status_code}.")) + } + responses[[i]] <- response + break + } + } } - response <- get( - res = "/archive/id/{id}", - id = id, - #callback = callback, # optional query parameter, perferred not to use, ave to understand how it works - .headers = req_headers(content_type = "application/json") - ) -} - -# # example -# result <- get_archive_id(id = "ENSG00000157764") -# print(result) -get_cafe_genetree_by_id <- function(id) { - if (missing(id)) { - stop("The 'id' parameter is required.") - } - response <- get( - res = glue::glue("/cafe/genetree/id/{id}"), - .headers = req_headers(content_type = "application/json") - ) + if (verbose) message("All requests completed.") + return(responses) } -# WE CAN THEN GO ON WITH OTHER ENDPOINTS WITH GET METHOD -# {the rest of the endpoints functions are in file `ensembl-endpoins.R`} diff --git a/man/dot-_get_divisions.Rd b/man/dot-_get_divisions.Rd new file mode 100755 index 0000000..d98d4e1 --- /dev/null +++ b/man/dot-_get_divisions.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{._get_divisions} +\alias{._get_divisions} +\title{Get list of all Ensembl divisions} +\usage{ +._get_divisions(callback = "randomlygeneratedname") +} +\arguments{ +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} +} +\value{ +A parsed JSON response containing the list of Ensembl divisions. + +See more about the implemented endpoint \code{\link[=._get_divisions]{._get_divisions()}} +on the following \href{https://rest.ensembl.org/documentation/info/info_divisions}{GET info/divisions} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves a list of all available Ensembl divisions for which information is accessible. +} +\examples{ +._get_divisions() +._get_divisions(callback = "randomlygeneratedname") +} diff --git a/man/dot-_get_rest_version.Rd b/man/dot-_get_rest_version.Rd new file mode 100755 index 0000000..7045efc --- /dev/null +++ b/man/dot-_get_rest_version.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{._get_rest_version} +\alias{._get_rest_version} +\title{Get REST API Version} +\usage{ +._get_rest_version(callback = "randomlygeneratedname") +} +\arguments{ +\item{callback}{(Optional) A string representing the name of the callback +subroutine for JSONP responses.} +} +\value{ +A parsed JSON response containing the REST API version information. + +See more about the implemented endpoint \code{\link[=._get_rest_version]{._get_rest_version()}} +on the following \href{https://rest.ensembl.org/documentation/info/rest}{GET info/rest} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves the current version of the Ensembl REST API. +} +\examples{ +._get_rest_version() +._get_rest_version(callback = "randomlygeneratedname") +} diff --git a/man/dot-_get_software_version.Rd b/man/dot-_get_software_version.Rd new file mode 100755 index 0000000..6209c78 --- /dev/null +++ b/man/dot-_get_software_version.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{._get_software_version} +\alias{._get_software_version} +\title{Get Software Version} +\usage{ +._get_software_version(callback = "randomlygeneratedname") +} +\arguments{ +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} +} +\value{ +A parsed JSON response containing the Ensembl API version information. + +See more about the implemented endpoint \code{\link[=._get_software_version]{._get_software_version()}} +on the following \href{https://rest.ensembl.org/documentation/info/software}{GET info/software} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves the current version of the Ensembl API used by the REST server. +} +\examples{ +._get_software_version() +._get_software_version(callback = "randomlygeneratedname") +} diff --git a/man/dot-_get_variation_sources.Rd b/man/dot-_get_variation_sources.Rd new file mode 100755 index 0000000..4b079a6 --- /dev/null +++ b/man/dot-_get_variation_sources.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{._get_variation_sources} +\alias{._get_variation_sources} +\title{Get Variation Sources for a Species} +\usage{ +._get_variation_sources( + species, + callback = "randomlygeneratedname", + filter = NULL +) +} +\arguments{ +\item{species}{(Required) A string representing the species name or alias (e.g., "homo_sapiens").} + +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} + +\item{filter}{(Optional) A string to restrict the variation source searches to a single source +(e.g., "dbSNP", "ClinVar", "OMIM", "UniProt", "HGMD").} +} +\value{ +A parsed JSON response containing the variation sources for the specified species. + +See more about the implemented endpoint \code{\link[=._get_variation_sources]{._get_variation_sources()}} +on the following \href{https://rest.ensembl.org/documentation/info/variation}{GET info/variation/:species} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves the variation sources used in Ensembl for a given species. +} +\examples{ +._get_variation_sources("homo_sapiens") +._get_variation_sources("homo_sapiens", filter = "ClinVar") +._get_variation_sources("homo_sapiens", callback = "randomlygeneratedname") +} diff --git a/man/get.Rd b/man/get.Rd index e2947b2..47c79eb 100755 --- a/man/get.Rd +++ b/man/get.Rd @@ -4,7 +4,7 @@ \alias{get} \title{The function for the GET method} \usage{ -get(res, ..., .headers = req_headers(), rate = 15/60) +get(res, ..., .headers = req_headers(), rate = 15/60, verbose = FALSE) } \arguments{ \item{res}{The resource (path) for the API request, can include variables @@ -17,6 +17,8 @@ in curly braces \code{{}} that will be replaced with the corresponding parameter \item{rate}{The maximum number of requests per second to allow. Defaults to 15 per minute (15/60).} + +\item{verbose}{Logical, if TRUE, enables detailed logging of request and response details.} } \value{ A list of responses, one for each request made. diff --git a/man/get_analysis_info.Rd b/man/get_analysis_info.Rd new file mode 100755 index 0000000..a462546 --- /dev/null +++ b/man/get_analysis_info.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_analysis_info} +\alias{get_analysis_info} +\title{Get the names of analyses involved in generating Ensembl data} +\usage{ +get_analysis_info(species, callback = "randomlygeneratedname") +} +\arguments{ +\item{species}{A string representing the species name or alias +(e.g., "homo_sapiens").} + +\item{callback}{(Optional) A string representing the name of the callback +subroutine for JSONP responses.} +} +\value{ +A list of analysis names related to the specified species. + +See more about the implemented endpoint \code{\link[=get_analysis_info]{get_analysis_info()}} +on the following \href{https://rest.ensembl.org/documentation/info/analysis}{GET info/analysis/:species} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves a list of analysis names associated with generating Ensembl +data for a given species. +} +\examples{ +get_analysis_info("homo_sapiens") +get_analysis_info("homo_sapiens", callback = "randomlygeneratedname") +} diff --git a/man/get_assembly_info.Rd b/man/get_assembly_info.Rd new file mode 100755 index 0000000..9286aee --- /dev/null +++ b/man/get_assembly_info.Rd @@ -0,0 +1,45 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_assembly_info} +\alias{get_assembly_info} +\title{Get the available assemblies for a species} +\usage{ +get_assembly_info( + species, + bands = 0, + synonyms = 0, + callback = "randomlygeneratedname" +) +} +\arguments{ +\item{species}{A string representing the species name or alias +(e.g., "homo_sapiens").} + +\item{bands}{(Optional) A boolean (0 or 1) indicating whether to +include karyotype band information. Default is 0.} + +\item{synonyms}{(Optional) A boolean (0 or 1) indicating whether to +include information about known synonyms. Default is 0.} + +\item{callback}{(Optional) A string representing the name of the callback +subroutine for JSONP responses.} +} +\value{ +A list of parsed JSON responses containing information about +the available assemblies for the specified species. + +See more about the implemented endpoint \code{\link[=get_assembly_info]{get_assembly_info()}} +on the following \href{https://rest.ensembl.org/documentation/info/assembly_info}{GET info/assembly/:species} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves a list of available assemblies for a given species, +including toplevel sequences, chromosomes, and optionally cytogenetic +bands and synonyms. +} +\examples{ +get_assembly_info("homo_sapiens") +get_assembly_info("homo_sapiens", bands = 1) +get_assembly_info("homo_sapiens", synonyms = 1, + callback = "randomlygeneratedname") +} diff --git a/man/get_biotypes.Rd b/man/get_biotypes.Rd new file mode 100755 index 0000000..d178875 --- /dev/null +++ b/man/get_biotypes.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_biotypes} +\alias{get_biotypes} +\title{Get the functional classifications of gene models for a species} +\usage{ +get_biotypes(species, callback = "randomlygeneratedname") +} +\arguments{ +\item{species}{A string representing the species name or alias (e.g., "homo_sapiens").} + +\item{callback}{(Optional) A string representing the name of the callback subroutine +for JSONP responses.} +} +\value{ +A list of parsed JSON responses containing the biotypes for the specified species. + +See more about the implemented endpoint \code{\link[=get_biotypes]{get_biotypes()}} +on the following \href{https://rest.ensembl.org/documentation/info/biotypes}{GET info/biotypes/:species} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves the list of functional classifications (biotypes) of gene models +that Ensembl associates with a particular species. +Useful for restricting the type of genes/transcripts retrieved by other endpoints. +} +\examples{ +get_biotypes("homo_sapiens") +get_biotypes("homo_sapiens", callback = "randomlygeneratedname") +} diff --git a/man/get_biotypes_by_name.Rd b/man/get_biotypes_by_name.Rd new file mode 100755 index 0000000..9b11e88 --- /dev/null +++ b/man/get_biotypes_by_name.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_biotypes_by_name} +\alias{get_biotypes_by_name} +\title{Get properties of biotypes by name} +\usage{ +get_biotypes_by_name( + name, + object_type = "", + callback = "randomlygeneratedname" +) +} +\arguments{ +\item{name}{A string representing the biotype name (e.g., "protein_coding").} + +\item{object_type}{(Optional) A string specifying the object type ("gene" or "transcript").} + +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} +} +\value{ +A list of parsed JSON responses containing the properties of biotypes with the given name. + +See more about the implemented endpoint \code{\link[=get_biotypes_by_name]{get_biotypes_by_name()}} +on the following \href{https://rest.ensembl.org/documentation/info/biotypes_name}{GET info/biotypes/name/:name/:object_type} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves the properties of biotypes with a given name. Optionally, the object type (gene or transcript) can be provided for filtering. +} +\examples{ +get_biotypes_by_name("protein_coding") +get_biotypes_by_name("protein_coding", object_type = "gene") +get_biotypes_by_name("protein_coding", object_type = "gene", callback = "randomlygeneratedname") +} diff --git a/man/get_biotypes_groups.Rd b/man/get_biotypes_groups.Rd new file mode 100755 index 0000000..b3253bc --- /dev/null +++ b/man/get_biotypes_groups.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_biotypes_groups} +\alias{get_biotypes_groups} +\title{Get properties of biotypes within a group} +\usage{ +get_biotypes_groups( + group = "", + object_type = "", + callback = "randomlygeneratedname" +) +} +\arguments{ +\item{group}{(Optional) A string representing the biotype group (e.g., "coding"). +If not provided, the available biotype groups are returned.} + +\item{object_type}{(Optional) A string specifying the object type ("gene" or "transcript").} + +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} +} +\value{ +A list of parsed JSON responses containing the properties of biotypes within +the specified group or all biotype groups if no group is provided. + +See more about the implemented endpoint \code{\link[=get_biotypes_groups]{get_biotypes_groups()}} +on the following \href{https://rest.ensembl.org/documentation/info/biotypes_groups}{GET info/biotypes/groups/:group/:object_type} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves a list of available biotype groups or, if a group is specified, +the properties of biotypes within that group. +Optionally, the object type (gene or transcript) can be used to filter the results. +} +\examples{ +get_biotypes_groups() +get_biotypes_groups(group = "coding") +get_biotypes_groups(group = "coding", object_type = "gene") +get_biotypes_groups(group = "coding", object_type = "gene", callback = "randomlygeneratedname") +} diff --git a/man/get_cafe_genetree_by_id.Rd b/man/get_cafe_genetree_by_id.Rd index 5725866..8e67031 100755 --- a/man/get_cafe_genetree_by_id.Rd +++ b/man/get_cafe_genetree_by_id.Rd @@ -4,7 +4,12 @@ \alias{get_cafe_genetree_by_id} \title{Get cafe gene tree by id} \usage{ -get_cafe_genetree_by_id(id) +get_cafe_genetree_by_id( + id, + callback = "myrandomfunctionname", + compara = "vertebrates", + nh_format = "simple" +) } \arguments{ \item{id}{A string representing the gene tree stable identifier.} diff --git a/man/get_cafe_genetree_by_species_id.Rd b/man/get_cafe_genetree_by_species_id.Rd index 8051daa..9a81de6 100755 --- a/man/get_cafe_genetree_by_species_id.Rd +++ b/man/get_cafe_genetree_by_species_id.Rd @@ -9,13 +9,16 @@ get_cafe_genetree_by_species_id(species, id) \arguments{ \item{species}{A string representing the species name (e.g., "homo_sapiens").} -\item{id}{A string representing the gene, transcript, or translation stable identifier.} +\item{id}{A string representing the gene, transcript, or translation +stable identifier.} } \value{ -A list of parsed JSON responses containing the cafe tree for the provided species and stable identifier. +A list of parsed JSON responses containing the cafe tree for +the provided species and stable identifier. } \description{ -Retrieves the cafe tree of the gene tree that contains the gene/transcript/translation stable identifier in the given species +Retrieves the cafe tree of the gene tree that contains the +gene/transcript/translation stable identifier in the given species } \note{ See more about the implemented endpoint \code{\link[=get_cafe_genetree_by_species_id]{get_cafe_genetree_by_species_id()}} diff --git a/man/get_cafe_genetree_by_symbol.Rd b/man/get_cafe_genetree_by_symbol.Rd index 5bdc7ac..7d7a7ad 100755 --- a/man/get_cafe_genetree_by_symbol.Rd +++ b/man/get_cafe_genetree_by_symbol.Rd @@ -7,8 +7,7 @@ get_cafe_genetree_by_symbol(species, symbol) } \arguments{ -\item{species}{A string representing the species name (e.g., -"homo_sapiens").} +\item{species}{A string representing the species name (e.g., "homo_sapiens").} \item{symbol}{A string representing the gene symbol (e.g., "BRCA2").} } diff --git a/man/get_compara_methods.Rd b/man/get_compara_methods.Rd new file mode 100755 index 0000000..3e22b65 --- /dev/null +++ b/man/get_compara_methods.Rd @@ -0,0 +1,38 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_compara_methods} +\alias{get_compara_methods} +\title{Get list of compara methods} +\usage{ +get_compara_methods( + callback = "randomlygeneratedname", + class = NULL, + compara = NULL +) +} +\arguments{ +\item{callback}{(Optional) A string representing the name of the callback subroutine +for JSONP responses.} + +\item{class}{(Optional) A string specifying the class of the method to query for. +Regular expression patterns are supported (e.g., "GenomicAlign").} + +\item{compara}{(Optional) A string representing the name of the compara database +to use (e.g., "vertebrates").} +} +\value{ +A list of parsed JSON responses containing all available compara methods. + +See more about the implemented endpoint \code{\link[=get_compara_methods]{get_compara_methods()}} +on the following \href{https://rest.ensembl.org/documentation/info/compara_methods}{GET info/compara/methods} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves a list of all compara analyses available (an analysis defines the type +of comparative data). Optional filtering by class or compara database can be applied. +} +\examples{ +get_compara_methods() +get_compara_methods(class = "GenomicAlign") +get_compara_methods(compara = "vertebrates", class = "GenomicAlign") +} diff --git a/man/get_compara_species_sets.Rd b/man/get_compara_species_sets.Rd new file mode 100755 index 0000000..778d75c --- /dev/null +++ b/man/get_compara_species_sets.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_compara_species_sets} +\alias{get_compara_species_sets} +\title{Get collections of species analysed with a specified compara method} +\usage{ +get_compara_species_sets( + method, + callback = "randomlygeneratedname", + compara = NULL +) +} +\arguments{ +\item{method}{A string representing the compara method to filter by (e.g., "EPO").} + +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} + +\item{compara}{(Optional) A string representing the name of the compara database to use (e.g., "vertebrates").} +} +\value{ +A list of parsed JSON responses containing all collections of species analysed with the specified compara method. + +See more about the implemented endpoint \code{\link[=get_compara_species_sets]{get_compara_species_sets()}} +on the following \href{https://rest.ensembl.org/documentation/info/compara_species_sets}{GET info/compara/species_sets/:method} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves a list of all collections of species analysed with the specified compara method. +The compara method must be one of the methods returned by the \verb{/info/compara/methods} endpoint. +} +\examples{ +get_compara_species_sets("EPO") +get_compara_species_sets("EPO", compara = "vertebrates") +} diff --git a/man/get_comparas.Rd b/man/get_comparas.Rd new file mode 100755 index 0000000..13c0175 --- /dev/null +++ b/man/get_comparas.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_comparas} +\alias{get_comparas} +\title{Get a list of all available comparative genomics databases and their data release} +\usage{ +get_comparas(callback = "randomlygeneratedname") +} +\arguments{ +\item{callback}{(Optional) A string representing the name of the callback subroutine +for JSONP responses.} +} +\value{ +A list of parsed JSON responses containing all available comparative genomics +databases and their data release. + +See more about the implemented endpoint \code{\link[=get_comparas]{get_comparas()}} +on the following \href{https://rest.ensembl.org/documentation/info/comparas}{GET info/comparas} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves a list of all available comparative genomics databases and their data release. +This endpoint is deprecated, and users are advised to use the \verb{/info/genomes/division} endpoint instead. +} +\examples{ +get_comparas() +} diff --git a/man/get_consequence_types.Rd b/man/get_consequence_types.Rd new file mode 100755 index 0000000..49ff41b --- /dev/null +++ b/man/get_consequence_types.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_consequence_types} +\alias{get_consequence_types} +\title{Get Variant Consequence Types} +\usage{ +get_consequence_types(callback = "randomlygeneratedname", rank = NULL) +} +\arguments{ +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} + +\item{rank}{(Optional) A boolean (0 or 1) to include consequence ranking in the response. Default is 0.} +} +\value{ +A parsed JSON response containing the list of variant consequence types. + +See more about the implemented endpoint \code{\link[=get_consequence_types]{get_consequence_types()}} +on the following \href{https://rest.ensembl.org/documentation/info/variation_consequence_types}{GET info/variation/consequence_types} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves a list of all variant consequence types available in Ensembl. +} +\examples{ +get_consequence_types() +get_consequence_types(rank = 1) +get_consequence_types(callback = "randomCallback") +} diff --git a/man/get_data.Rd b/man/get_data.Rd new file mode 100755 index 0000000..28de98c --- /dev/null +++ b/man/get_data.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_data} +\alias{get_data} +\title{Get a list of available data releases on the Ensembl REST server} +\usage{ +get_data(callback = "randomlygeneratedname") +} +\arguments{ +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} +} +\value{ +A list of parsed JSON responses containing the available data releases on the Ensembl REST server. + +See more about the implemented endpoint \code{\link[=get_data]{get_data()}} +on the following \href{https://rest.ensembl.org/documentation/info/data}{GET info/data} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves a list of the data releases available on the Ensembl REST server. It may return more than one release if the server has an unfrequent, non-standard configuration. +} +\examples{ +get_data() +} diff --git a/man/get_eg_version.Rd b/man/get_eg_version.Rd new file mode 100755 index 0000000..66f671b --- /dev/null +++ b/man/get_eg_version.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_eg_version} +\alias{get_eg_version} +\title{Get the Ensembl Genomes version of the databases backing the service} +\usage{ +get_eg_version(callback = "randomlygeneratedname") +} +\arguments{ +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} +} +\value{ +A parsed JSON response containing the Ensembl Genomes version of the databases. + +See more about the implemented endpoint \code{\link[=get_eg_version]{get_eg_version()}} +on the following \href{https://rest.ensembl.org/documentation/info/eg_version}{GET info/eg_version} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves the Ensembl Genomes version of the databases supporting the current service. +} +\examples{ +get_eg_version() +} diff --git a/man/get_external_dbs.Rd b/man/get_external_dbs.Rd new file mode 100755 index 0000000..49c2bcb --- /dev/null +++ b/man/get_external_dbs.Rd @@ -0,0 +1,40 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_external_dbs} +\alias{get_external_dbs} +\title{Get external databases for a species} +\usage{ +get_external_dbs( + species, + callback = "randomlygeneratedname", + feature = NULL, + filter = NULL +) +} +\arguments{ +\item{species}{A string representing the species name or alias (e.g., "homo_sapiens").} + +\item{callback}{(Optional) A string representing the name of the callback subroutine +for JSONP responses.} + +\item{feature}{(Optional) A string representing the feature to filter external DB entries +(e.g., "dna_align_feature", "protein_align_feature", "unmapped_object", "xref", "seq_region_synonym").} + +\item{filter}{(Optional) A string to restrict external DB searches to a single source +or pattern (e.g., "HGNC", "GO\%").} +} +\value{ +A parsed JSON response containing a list of external sources associated +with the given species. + +See more about the implemented endpoint \code{\link[=get_external_dbs]{get_external_dbs()}} +on the following \href{https://rest.ensembl.org/documentation/info/external_dbs}{GET info/external_dbs/:species} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves a list of all available external sources for a given species. +} +\examples{ +get_external_dbs("homo_sapiens") +get_external_dbs("homo_sapiens", feature = "xref", filter = "HGNC") +} diff --git a/man/get_genetree_by_id.Rd b/man/get_genetree_by_id.Rd index 5915b5d..56da720 100755 --- a/man/get_genetree_by_id.Rd +++ b/man/get_genetree_by_id.Rd @@ -10,7 +10,8 @@ get_genetree_by_id(id) \item{id}{A string representing the gene tree stable identifier.} } \value{ -A list of parsed JSON responses containing the gene tree for the provided gene tree stable identifier. +A list of parsed JSON responses containing the gene tree for +the provided gene tree stable identifier. } \description{ Retrieves a gene tree for a gene tree stable identifier diff --git a/man/get_genome_info.Rd b/man/get_genome_info.Rd new file mode 100755 index 0000000..be4eed9 --- /dev/null +++ b/man/get_genome_info.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_genome_info} +\alias{get_genome_info} +\title{Get genome information} +\usage{ +get_genome_info(name, callback = "randomlygeneratedname", expand = NULL) +} +\arguments{ +\item{name}{(Required) A string representing the production name of the genome +(e.g., "arabidopsis_thaliana").} + +\item{callback}{(Optional) A string representing the name of the callback subroutine +for JSONP responses.} + +\item{expand}{(Optional) A boolean value (0 or 1). If set to 1, expands +the information to include details of sequences (can be very large). +Default is NULL.} +} +\value{ +A parsed JSON response containing information about the specified genome. + +See more about the implemented endpoint \code{\link[=get_genome_info]{get_genome_info()}} +on the following \href{https://rest.ensembl.org/documentation/info/info_genome}{GET info/genomes/:genome_name} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves detailed information about a given genome based on its production name. +} +\examples{ +get_genome_info(name = "arabidopsis_thaliana") +get_genome_info(name = "arabidopsis_thaliana", expand = 1) +get_genome_info(name = "arabidopsis_thaliana", callback = "randomlygeneratedname") +} diff --git a/man/get_genome_info_by_accession.Rd b/man/get_genome_info_by_accession.Rd new file mode 100755 index 0000000..2a0e293 --- /dev/null +++ b/man/get_genome_info_by_accession.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_genome_info_by_accession} +\alias{get_genome_info_by_accession} +\title{Get genome information by INSDC accession} +\usage{ +get_genome_info_by_accession( + accession, + callback = "randomlygeneratedname", + expand = NULL +) +} +\arguments{ +\item{accession}{(Required) A string representing the INSDC sequence accession (optionally versioned), e.g., "U00096".} + +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} + +\item{expand}{(Optional) A boolean value (0 or 1). If set to 1, expands the information to include details of sequences (can be very large).} +} +\value{ +A parsed JSON response containing information about genomes with the specified INSDC accession. + +See more about the implemented endpoint \code{\link[=get_genome_info_by_accession]{get_genome_info_by_accession()}} +on the following \href{https://rest.ensembl.org/documentation/info/info_genomes_accession}{GET info/genomes/accession/:accession} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves detailed information about genomes containing a specified INSDC accession. +} +\examples{ +get_genome_info_by_accession(accession = "U00096") +get_genome_info_by_accession(accession = "U00096", expand = 1) +get_genome_info_by_accession(accession = "U00096", callback = "randomlygeneratedname") +} diff --git a/man/get_genome_info_by_assembly.Rd b/man/get_genome_info_by_assembly.Rd new file mode 100755 index 0000000..74c2598 --- /dev/null +++ b/man/get_genome_info_by_assembly.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_genome_info_by_assembly} +\alias{get_genome_info_by_assembly} +\title{Get genome information by assembly ID} +\usage{ +get_genome_info_by_assembly( + assembly_id, + callback = "randomlygeneratedname", + expand = NULL +) +} +\arguments{ +\item{assembly_id}{(Required) A string representing the INSDC assembly ID (optionally versioned, e.g., "GCA_902167145.1").} + +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} + +\item{expand}{(Optional) A boolean value (0 or 1). If set to 1, expands the information +to include details of sequences (can be very large).} +} +\value{ +A parsed JSON response containing information about the genome associated +with the specified assembly ID. + +See more about the implemented endpoint \code{\link[=get_genomes_by_assembly]{get_genomes_by_assembly()}} +on the following \href{https://rest.ensembl.org/documentation/info/info_genomes_assembly}{GET info/genomes/assembly/:assembly_id} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves information about a genome associated with a specified assembly ID. +} +\examples{ +get_genome_info_by_assembly(assembly_id = "GCA_902167145.1") +get_genome_info_by_assembly(assembly_id = "GCA_902167145.1", expand = 1) +get_genome_info_by_assembly(assembly_id = "GCA_902167145.1", callback = "randomlygeneratedname") +} diff --git a/man/get_genome_info_by_division.Rd b/man/get_genome_info_by_division.Rd new file mode 100755 index 0000000..4de3141 --- /dev/null +++ b/man/get_genome_info_by_division.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_genome_info_by_division} +\alias{get_genome_info_by_division} +\title{Get genome information for a specific division} +\usage{ +get_genome_info_by_division( + division_name, + callback = "randomlygeneratedname", + expand = NULL +) +} +\arguments{ +\item{division_name}{(Required) A string representing the name of the division (e.g., "EnsemblPlants").} + +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} + +\item{expand}{(Optional) A boolean value (0 or 1). If set to 1, expands the information to include details of sequences (can be very large).} +} +\value{ +A parsed JSON response containing information about genomes in the specified division. + +See more about the implemented endpoint \code{\link[=get_genomes_by_division]{get_genomes_by_division()}} +on the following \href{https://rest.ensembl.org/documentation/info/info_genomes_division}{GET info/genomes/division/:division_name} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves information about all genomes in a given division. +Note: The response may be very large for divisions like Ensembl Bacteria. +} +\examples{ +get_genome_info_by_division(division_name = "EnsemblPlants") +get_genome_info_by_division(division_name = "EnsemblPlants", expand = 1) +get_genome_info_by_division(division_name = "EnsemblPlants", callback = "randomlygeneratedname") +} diff --git a/man/get_genome_info_by_taxonomy.Rd b/man/get_genome_info_by_taxonomy.Rd new file mode 100755 index 0000000..0fc2150 --- /dev/null +++ b/man/get_genome_info_by_taxonomy.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_genome_info_by_taxonomy} +\alias{get_genome_info_by_taxonomy} +\title{Get genome information by taxonomy node} +\usage{ +get_genome_info_by_taxonomy( + taxon_name, + callback = "randomlygeneratedname", + expand = NULL +) +} +\arguments{ +\item{taxon_name}{(Required) A string representing the taxon name or NCBI taxonomy ID (e.g., "Homo sapiens").} + +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} + +\item{expand}{(Optional) A boolean value (0 or 1). If set to 1, expands the information +to include details of sequences (can be very large).} +} +\value{ +A parsed JSON response containing information about genomes beneath the specified taxonomy node. + +See more about the implemented endpoint \code{\link[=get_genomes_by_taxonomy]{get_genomes_by_taxonomy()}} +on the following \href{https://rest.ensembl.org/documentation/info/info_genomes_taxonomy}{GET info/genomes/taxonomy/:taxon_name} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves information about all genomes beneath a given node of the taxonomy. +} +\examples{ +get_genome_info_by_taxonomy(taxon_name = "Homo sapiens") +get_genome_info_by_taxonomy(taxon_name = "Homo sapiens", expand = 1) +get_genome_info_by_taxonomy(taxon_name = "Homo sapiens", callback = "randomlygeneratedname") +} diff --git a/man/get_population_individuals.Rd b/man/get_population_individuals.Rd new file mode 100755 index 0000000..b75fc44 --- /dev/null +++ b/man/get_population_individuals.Rd @@ -0,0 +1,38 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_population_individuals} +\alias{get_population_individuals} +\title{Get Population Individuals} +\usage{ +get_population_individuals( + species, + population_name, + callback = "randomlygeneratedname" +) +} +\arguments{ +\item{species}{(Required) A string representing the species name or alias (e.g., "human").} + +\item{population_name}{(Required) A string representing the name of the population (e.g., "1000GENOMES:phase_3:ASW").} + +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} +} +\value{ +A parsed JSON response containing the list of individuals for the specified population. + +See more about the implemented endpoint \code{\link[=get_population_individuals]{get_population_individuals()}} +on the following \href{https://rest.ensembl.org/documentation/info/variation_population_name}{GET info/variation/populations/:species/:population_name} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves a list of all individuals for a specified population from a species in Ensembl. +} +\examples{ +get_population_individuals(species = "human", population_name = "1000GENOMES:phase_3:ASW") +get_population_individuals(species = "homo_sapiens", population_name = "1000GENOMES:phase_3:YRI") +get_population_individuals( + species = "human", + population_name = "1000GENOMES:phase_3:CEU", + callback = "randomCallback" +) +} diff --git a/man/get_region_info.Rd b/man/get_region_info.Rd new file mode 100755 index 0000000..ca8a0d3 --- /dev/null +++ b/man/get_region_info.Rd @@ -0,0 +1,45 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_region_info} +\alias{get_region_info} +\title{Get information about a specific toplevel sequence region for a species} +\usage{ +get_region_info( + species, + region_name, + bands = 0, + synonyms = 0, + callback = "randomlygeneratedname" +) +} +\arguments{ +\item{species}{A string representing the species name or alias (e.g., "homo_sapiens").} + +\item{region_name}{A string representing the name of the toplevel sequence region (e.g., "X").} + +\item{bands}{(Optional) A boolean (0 or 1) indicating whether to include +karyotype band information. Default is 0.} + +\item{synonyms}{(Optional) A boolean (0 or 1) indicating whether to include +information about known synonyms. Default is 0.} + +\item{callback}{(Optional) A string representing the name of the callback +subroutine for JSONP responses.} +} +\value{ +A list of parsed JSON responses containing information about +the specified sequence region for the given species. + +See more about the implemented endpoint \code{\link[=get_region_info]{get_region_info()}} +on the following \href{https://rest.ensembl.org/documentation/info/assembly_stats}{GET info/assembly/:species/:region_name} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves information about the specified toplevel sequence region for +a given species, with optional details on karyotype bands and synonyms. +} +\examples{ +get_region_info("homo_sapiens", "X") +get_region_info("homo_sapiens", "X", bands = 1) +get_region_info("homo_sapiens", "X", synonyms = 1, callback = "randomlygeneratedname") +} diff --git a/man/get_species_info.Rd b/man/get_species_info.Rd new file mode 100755 index 0000000..4e8cf6a --- /dev/null +++ b/man/get_species_info.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_species_info} +\alias{get_species_info} +\title{Get Species Information} +\usage{ +get_species_info( + callback = "randomlygeneratedname", + division = "EnsemblVertebrates", + hide_strain_info = 0, + strain_collection = NULL +) +} +\arguments{ +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} + +\item{division}{(Optional) A string to filter by Ensembl or Ensembl Genomes division (default is "EnsemblVertebrates").} + +\item{hide_strain_info}{(Optional) A boolean flag to show/hide strain and +strain_collection information (default is 0, which shows strain info).} + +\item{strain_collection}{(Optional) A string to filter by strain collection (e.g., "mouse").} +} +\value{ +A parsed JSON response containing species information. + +See more about the implemented endpoint \code{\link[=get_species_info]{get_species_info()}} +on the following \href{https://rest.ensembl.org/documentation/info/species}{GET info/species} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves a list of all available species, their aliases, available adaptor groups, and data release. +} +\examples{ +get_species_info() +get_species_info(division = "EnsemblPlants") +get_species_info(hide_strain_info = 1) +get_species_info(strain_collection = "mouse") +} diff --git a/man/get_species_populations.Rd b/man/get_species_populations.Rd new file mode 100755 index 0000000..c565c2d --- /dev/null +++ b/man/get_species_populations.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_species_populations} +\alias{get_species_populations} +\title{Get Populations for a Species} +\usage{ +get_species_populations( + species, + callback = "randomlygeneratedname", + filter = NULL +) +} +\arguments{ +\item{species}{(Required) A string representing the species name or alias (e.g., "homo_sapiens").} + +\item{callback}{(Optional) A string representing the name of the callback subroutine for JSONP responses.} + +\item{filter}{(Optional) A string to restrict populations returned +(e.g., "LD" to filter populations with linkage disequilibrium data).} +} +\value{ +A parsed JSON response containing the list of populations for the specified species. + +See more about the implemented endpoint \code{\link[=get_species_populations]{get_species_populations()}} +on the following \href{https://rest.ensembl.org/documentation/info/variation_populations}{GET info/variation/populations/:species} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Retrieves a list of all populations for a specified species in Ensembl. +} +\examples{ +get_species_populations(species = "homo_sapiens") +get_species_populations(species = "human", filter = "LD") +get_species_populations( + species = "homo_sapiens", + callback = "randomlygeneratedname", + filter = "LD" +) +} diff --git a/man/ping_service.Rd b/man/ping_service.Rd new file mode 100755 index 0000000..6136b87 --- /dev/null +++ b/man/ping_service.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{ping_service} +\alias{ping_service} +\title{Check Service Status} +\usage{ +ping_service(callback = "randomlygeneratedname") +} +\arguments{ +\item{callback}{(Optional) A string representing the name of the callback +subroutine for JSONP responses.} +} +\value{ +A parsed JSON response indicating the status of the service. + +See more about the implemented endpoint \code{\link[=ping_service]{ping_service()}} +on the following \href{https://rest.ensembl.org/documentation/info/ping}{GET info/ping} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Sends a ping request to the server to check if the service is alive. +} +\examples{ +ping_service() +ping_service(callback = "randomlygeneratedname") +} From d4b134d6bc047a34b5063c9812e8332d1f9fd32c Mon Sep 17 00:00:00 2001 From: danymukesha Date: Tue, 24 Dec 2024 20:39:20 +0100 Subject: [PATCH 27/28] correct error in function: get_analysis_info("homo_sapiens") --- R/ensembl-endpoints.R | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/R/ensembl-endpoints.R b/R/ensembl-endpoints.R index 53a7e63..7715de5 100755 --- a/R/ensembl-endpoints.R +++ b/R/ensembl-endpoints.R @@ -414,11 +414,22 @@ get_analysis_info <- function(species, callback = "randomlygeneratedname") { stop("'species' parameter is required.") } if (!is.null(callback)) { - response <- get(res = "/info/analysis/{species}", species = species, - .headers = req_headers(content_type = "application/json"), callback) + query_params <- list() + if (!is.null(species)) query_params$species <- species + if (!is.null(callback)) query_params$callback <- callback + + headers <- req_headers(content_type = "application/json") + + response <- + do.call(get, + c(list( + res = "/info/analysis/{species}", + .headers = headers), + query_params) + ) } else { - response <- get(res = "/info/analysis/{species}", species = species, - .headers = req_headers(content_type = "application/json")) + warning("Callback is null. Returning an empty response.") + response <- list() } response From f751991ac41959ea342f0c0bab4f3f4947490cbd Mon Sep 17 00:00:00 2001 From: danymukesha Date: Fri, 14 Feb 2025 17:12:25 +0100 Subject: [PATCH 28/28] add functions and unit tests for endpoints from `Linkage Disequilibrium` --- NAMESPACE | 3 + R/callback_warning.R | 8 + R/ensembl-endpoints.R | 236 ++++++++++++++++++++++++++++- R/get.R | 2 +- R/post.R | 2 +- man/get.Rd | 2 +- man/get_divisions.Rd | 0 man/get_genome_info_by_assembly.Rd | 2 +- man/get_genome_info_by_division.Rd | 2 +- man/get_genome_info_by_taxonomy.Rd | 2 +- man/get_ld_by_variant.Rd | 70 +++++++++ man/get_ld_values_by_region.Rd | 65 ++++++++ man/get_pairwise_ld_values.Rd | 61 ++++++++ man/get_variation_sources.Rd | 0 man/post.Rd | 2 +- tests/testthat/test-endpoints.R | 58 +++++++ 16 files changed, 503 insertions(+), 12 deletions(-) create mode 100755 R/callback_warning.R mode change 100644 => 100755 man/get_divisions.Rd create mode 100755 man/get_ld_by_variant.Rd create mode 100755 man/get_ld_values_by_region.Rd create mode 100755 man/get_pairwise_ld_values.Rd mode change 100644 => 100755 man/get_variation_sources.Rd diff --git a/NAMESPACE b/NAMESPACE index 2229fea..6ef8923 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -42,10 +42,13 @@ export(get_homology_by_symbol) export(get_id) export(get_individuals) export(get_karyotypes) +export(get_ld_by_variant) +export(get_ld_values_by_region) export(get_ld_variants_by_pair) export(get_ld_variants_by_pair_combn) export(get_ld_variants_by_range) export(get_ld_variants_by_window) +export(get_pairwise_ld_values) export(get_population_individuals) export(get_populations) export(get_region_info) diff --git a/R/callback_warning.R b/R/callback_warning.R new file mode 100755 index 0000000..584ebd8 --- /dev/null +++ b/R/callback_warning.R @@ -0,0 +1,8 @@ +callback_warning <- function() { + warning( + "This happen when `callback` is NULL. We are working on it. + if you are curious please checkout for more info: + https://github.com/Ensembl/ensembl-rest/wiki/CORS-And-JSONP#json-p or + https://httr2.r-lib.org/reference/req_perform_stream.html" + ) +} diff --git a/R/ensembl-endpoints.R b/R/ensembl-endpoints.R index 7715de5..3087f62 100755 --- a/R/ensembl-endpoints.R +++ b/R/ensembl-endpoints.R @@ -1046,7 +1046,7 @@ get_genome_info_by_accession <- function(accession, callback = "randomlygenerate #' @return A parsed JSON response containing information about the genome associated #' with the specified assembly ID. #' -#' See more about the implemented endpoint [get_genomes_by_assembly()] +#' See more about the implemented endpoint [get_genome_info_by_assembly()] #' on the following [GET info/genomes/assembly/:assembly_id](https://rest.ensembl.org/documentation/info/info_genomes_assembly) #' from the official [Ensembl Rest API](https://rest.ensembl.org/). #' @@ -1094,7 +1094,7 @@ get_genome_info_by_assembly <- function(assembly_id, callback = "randomlygenerat #' #' @return A parsed JSON response containing information about genomes in the specified division. #' -#' See more about the implemented endpoint [get_genomes_by_division()] +#' See more about the implemented endpoint [get_genome_info_by_division()] #' on the following [GET info/genomes/division/:division_name](https://rest.ensembl.org/documentation/info/info_genomes_division) #' from the official [Ensembl Rest API](https://rest.ensembl.org/). #' @@ -1142,7 +1142,7 @@ get_genome_info_by_division <- function(division_name, callback = "randomlygener #' #' @return A parsed JSON response containing information about genomes beneath the specified taxonomy node. #' -#' See more about the implemented endpoint [get_genomes_by_taxonomy()] +#' See more about the implemented endpoint [get_genome_info_by_taxonomy()] #' on the following [GET info/genomes/taxonomy/:taxon_name](https://rest.ensembl.org/documentation/info/info_genomes_taxonomy) #' from the official [Ensembl Rest API](https://rest.ensembl.org/). #' @@ -1499,7 +1499,7 @@ get_species_populations <- function(species, callback = "randomlygeneratedname", if (!is.null(callback)) { query_params <- list() - if (!is.null(species)) query_params$species <- species + query_params$species <- species if (!is.null(filter)) query_params$filter <- filter if (!is.null(callback)) query_params$callback <- callback @@ -1520,10 +1520,236 @@ get_species_populations <- function(species, callback = "randomlygeneratedname", response } - # -------------------------------------------------------- # ## Linkage Disequilibrium ==== +#' Get Linkage Disequilibrium (LD) values +#' +#' Computes and retrieves LD values between a given variant and all other +#' variants within a window of up to 500 kb in the specified population. +#' +#' @param species A string representing the species name +#' or alias. +#' @param id A string representing the variant ID +#' (e.g., rs56116432). +#' @param population_name A string representing the population +#' for which to compute LD. +#' Use GET /info/variation/populations/:species?filter=LD to +#' retrieve a list of all populations with LD data. This endpoint is already +#' implemented. Please, use [get_species_populations()] with filter "LD" +#' to retrieve valid populations. +#' @param attribs \emph{(Optional)} A boolean indicating whether +#' to add variation attributes such as chromosome, start, end, strand, +#' consequence type, and clinical significance. Default is NULL. +#' @param callback \emph{(Optional)} A string representing the name of the +#' callback subroutine for JSONP responses. +#' @param d_prime \emph{(Optional)} A float value (0-1) to filter results +#' by D' (linkage disequilibrium measure). Only returns pairs with D' ≥ +#' the specified value. Default is NULL. +#' @param r2 \emph{(Optional)} A float value (0-1) to filter results by +#' r² (correlation coefficient). Only returns pairs with r² ≥ the specified +#' value.. Default is NULL. +#' @param window_size \emph{(Optional)} An integer specifying the window size +#' in kb (max 500). Defaults to 500 kb. +#' +#' @return A list of parsed JSON responses containing the LD values for +#' the provided variant. +#' +#' @note +#' See more about the implemented endpoint [get_ld_by_variant()] +#' on the following [GET ld/:species/:id/:population_name](https://rest.ensembl.org/documentation/info/ld) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_ld_by_variant("homo_sapiens", "rs56116432", "1000GENOMES:phase_3:KHV") +#' get_ld_by_variant("homo_sapiens", "rs56116432", "1000GENOMES:phase_3:KHV", +#' d_prime = 0.8, r2 = 0.85) +#' get_ld_by_variant("homo_sapiens", "rs56116432", "1000GENOMES:phase_3:KHV", +#' window_size = 250) +#' +get_ld_by_variant <- function(species, id, population_name, attribs = NULL, + callback = "randomlygeneratedname", + d_prime = NULL, r2 = NULL, + window_size = 500) { + if (missing(species) || missing(id) || missing(population_name)) { + stop("'species', 'id', and 'population_name' parameters are all required.") + } + + if (!is.null(window_size) && (window_size < 1 || window_size > 500)) { + stop("'window_size' parameter must be between 1 and 500 kb.") + } + + if (!is.null(callback)) { + query_params <- list() + query_params$species <- species + query_params$id <- id + query_params$population_name <- population_name + if (!is.null(attribs)) query_params$attribs <- as.integer(attribs) + if (!is.null(d_prime)) query_params$d_prime <- d_prime + if (!is.null(r2)) query_params$r2 <- r2 + if (!is.null(window_size)) query_params$window_size <- window_size + + headers <- req_headers(content_type = "application/json") + + response <- do.call(get, c(list( + res = "/ld/{species}/{id}/{population_name}", + .headers = headers), + query_params)) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get Pairwise Linkage Disequilibrium (LD) Values +#' +#' Computes and retrieves LD values between two given variants. +#' +#' @param species A string representing the species name or +#' alias (e.g., "homo_sapiens"). +#' @param id1 A string representing the first variant ID +#' (e.g., "rs6792369"). +#' @param id2 A string representing the second variant ID +#' (e.g., "rs1042779"). +#' @param callback \emph{(Optional)} A string representing the name of +#' the callback +#' subroutine for JSONP responses. +#' @param d_prime \emph{(Optional)} A float value (0-1) to filter results +#' by D' (linkage disequilibrium measure). +#' Only returns pairs with D' ≥ the specified value. +#' @param r2 \emph{(Optional)} A float value (0-1) to filter results by r² +#' (correlation coefficient). Only returns pairs with r² ≥ the specified value. +#' @param population_name \emph{(Optional)} A string representing the population +#' for which to compute LD. Use [get_species_populations()] with filter "LD" +#' to retrieve valid populations. +#' +#' @return A parsed JSON response containing the LD values for the specified +#' variant pair. +#' +#' See more about the implemented endpoint [get_pairwise_ld_values()] +#' on the following [GET ld/:species/pairwise/:id1/:id2](https://rest.ensembl.org/documentation/info/ld_pairwise) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_pairwise_ld_values(species = "homo_sapiens", id1 = "rs6792369", +#' id2 = "rs1042779") +#' get_pairwise_ld_values(species = "homo_sapiens", id1 = "rs6792369", +#' id2 = "rs1042779", r2 = 0.85) +#' get_pairwise_ld_values(species = "homo_sapiens", id1 = "rs6792369", +#' id2 = "rs1042779", d_prime = 1.0, +#' population_name = "1000GENOMES:phase_3:KHV") +get_pairwise_ld_values <- function(species, id1, id2, + callback = "randomlygeneratedname", + d_prime = NULL, r2 = NULL, + population_name = NULL) { + if (missing(species) || missing(id1) || missing(id2)) { + stop("'species', 'id1', and 'id2' parameters are all required.") + } + + if (!is.null(callback)) { + query_params <- list() + query_params$species <- species + query_params$id1 <- id1 + query_params$id2 <- id2 + if (!is.null(d_prime)) query_params$d_prime <- d_prime + if (!is.null(r2)) query_params$r2 <- r2 + if (!is.null(population_name)) query_params$population_name <- population_name + + headers <- req_headers(content_type = "application/json") + + response <- do.call(get, c(list( + res = "/ld/{species}/pairwise/{id1}/{id2}", + .headers = headers), + query_params)) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + +#' Get Linkage Disequilibrium (LD) Values for a Genomic Region +#' +#' Computes and retrieves LD values between all pairs of variants within +#' a defined genomic region. +#' +#' @param species A string representing the species name or alias +#' (e.g., "homo_sapiens"). +#' @param region A string defining the genomic region in the format +#' "chr:start..end". +#' The maximum region size allowed is 500 kb. If the region overlaps +#' the MHC region, the maximum is 10 kb. +#' @param population_name A string representing the population for which +#' LD should be computed. +#' Use [get_species_populations()] with filter "LD" to retrieve valid +#' populations. +#' @param callback \emph{(Optional)} A string representing the name of the +#' callback subroutine for JSONP responses. +#' @param d_prime \emph{(Optional)} A float value (0-1) to filter results +#' by D' (linkage disequilibrium measure). +#' Only returns pairs with D' ≥ the specified value. +#' @param r2 \emph{(Optional)} A float value (0-1) to filter results by r² +#' (correlation coefficient). +#' Only returns pairs with r² ≥ the specified value. +#' +#' @return A parsed JSON response containing the LD values for all variant +#' pairs within the specified region. +#' +#' See more about the implemented endpoint [get_ld_values_by_region()] +#' on the following [GET ld/:species/region/:region/:population_name](https://rest.ensembl.org/documentation/info/ld_region) +#' from the official [Ensembl Rest API](https://rest.ensembl.org/). +#' +#' @export +#' @examples +#' get_ld_values_by_region(species = "homo_sapiens", +#' region = "6:25837556..25843455", +#' population_name = "1000GENOMES:phase_3:KHV") +#' get_ld_values_by_region(species = "homo_sapiens", +#' region = "6:25837556..25843455", +#' population_name = "1000GENOMES:phase_3:KHV", +#' r2 = 0.85) +#' get_ld_values_by_region(species = "homo_sapiens", +#' region = "6:25837556..25843455", +#' population_name = "1000GENOMES:phase_3:KHV", +#' d_prime = 1.0) +get_ld_values_by_region <- function(species, region, population_name, + callback = "randomlygeneratedname", + d_prime = NULL, r2 = NULL) { + if (missing(species) || missing(region) || missing(population_name)) { + stop("'species', 'region', and 'population_name' parameters are all required.") + } + + if (!is.null(callback)) { + query_params <- list() + query_params$species <- species + query_params$region <- region + query_params$population_name <- population_name + if (!is.null(d_prime)) query_params$d_prime <- d_prime + if (!is.null(r2)) query_params$r2 <- r2 + + headers <- req_headers(content_type = "application/json") + + response <- do.call(get, c(list( + res = "/ld/{species}/region/{region}/{population_name}", + .headers = headers), + query_params)) + + } else { + warning("Callback is null. Returning an empty response.") + response <- list() + } + + response +} + + # -------------------------------------------------------- # ## Lookup ==== diff --git a/R/get.R b/R/get.R index 9b8618c..5abf18c 100755 --- a/R/get.R +++ b/R/get.R @@ -1,6 +1,6 @@ #' The function for the GET method #' -#' The [get()] function is a wrapper around the [reqs()] function that performs +#' The [get()] function is a wrapper around the `reqs` function that performs #' GET requests to the Ensembl API, handling rate limiting automatically. #' #' @param res The resource (path) for the API request, can include variables diff --git a/R/post.R b/R/post.R index e256187..f2a1102 100755 --- a/R/post.R +++ b/R/post.R @@ -1,6 +1,6 @@ #' The function for POST method #' -#' The [post()] function is a wrapper around the [reqs()] function that +#' The [post()] function is a wrapper around the `reqs` function that #' performs POST requests to the Ensembl API, handling rate limiting #' automatically. #' diff --git a/man/get.Rd b/man/get.Rd index 47c79eb..e48c593 100755 --- a/man/get.Rd +++ b/man/get.Rd @@ -24,7 +24,7 @@ Defaults to 15 per minute (15/60).} A list of responses, one for each request made. } \description{ -The \code{\link[=get]{get()}} function is a wrapper around the \code{\link[=reqs]{reqs()}} function that performs +The \code{\link[=get]{get()}} function is a wrapper around the \code{reqs} function that performs GET requests to the Ensembl API, handling rate limiting automatically. } \keyword{internal} diff --git a/man/get_divisions.Rd b/man/get_divisions.Rd old mode 100644 new mode 100755 diff --git a/man/get_genome_info_by_assembly.Rd b/man/get_genome_info_by_assembly.Rd index 74c2598..8ee8992 100755 --- a/man/get_genome_info_by_assembly.Rd +++ b/man/get_genome_info_by_assembly.Rd @@ -22,7 +22,7 @@ to include details of sequences (can be very large).} A parsed JSON response containing information about the genome associated with the specified assembly ID. -See more about the implemented endpoint \code{\link[=get_genomes_by_assembly]{get_genomes_by_assembly()}} +See more about the implemented endpoint \code{\link[=get_genome_info_by_assembly]{get_genome_info_by_assembly()}} on the following \href{https://rest.ensembl.org/documentation/info/info_genomes_assembly}{GET info/genomes/assembly/:assembly_id} from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. } diff --git a/man/get_genome_info_by_division.Rd b/man/get_genome_info_by_division.Rd index 4de3141..a9a4cf6 100755 --- a/man/get_genome_info_by_division.Rd +++ b/man/get_genome_info_by_division.Rd @@ -20,7 +20,7 @@ get_genome_info_by_division( \value{ A parsed JSON response containing information about genomes in the specified division. -See more about the implemented endpoint \code{\link[=get_genomes_by_division]{get_genomes_by_division()}} +See more about the implemented endpoint \code{\link[=get_genome_info_by_division]{get_genome_info_by_division()}} on the following \href{https://rest.ensembl.org/documentation/info/info_genomes_division}{GET info/genomes/division/:division_name} from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. } diff --git a/man/get_genome_info_by_taxonomy.Rd b/man/get_genome_info_by_taxonomy.Rd index 0fc2150..cdff624 100755 --- a/man/get_genome_info_by_taxonomy.Rd +++ b/man/get_genome_info_by_taxonomy.Rd @@ -21,7 +21,7 @@ to include details of sequences (can be very large).} \value{ A parsed JSON response containing information about genomes beneath the specified taxonomy node. -See more about the implemented endpoint \code{\link[=get_genomes_by_taxonomy]{get_genomes_by_taxonomy()}} +See more about the implemented endpoint \code{\link[=get_genome_info_by_taxonomy]{get_genome_info_by_taxonomy()}} on the following \href{https://rest.ensembl.org/documentation/info/info_genomes_taxonomy}{GET info/genomes/taxonomy/:taxon_name} from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. } diff --git a/man/get_ld_by_variant.Rd b/man/get_ld_by_variant.Rd new file mode 100755 index 0000000..47fbfb7 --- /dev/null +++ b/man/get_ld_by_variant.Rd @@ -0,0 +1,70 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_ld_by_variant} +\alias{get_ld_by_variant} +\title{Get Linkage Disequilibrium (LD) values} +\usage{ +get_ld_by_variant( + species, + id, + population_name, + attribs = NULL, + callback = "randomlygeneratedname", + d_prime = NULL, + r2 = NULL, + window_size = 500 +) +} +\arguments{ +\item{species}{A string representing the species name +or alias.} + +\item{id}{A string representing the variant ID +(e.g., rs56116432).} + +\item{population_name}{A string representing the population +for which to compute LD. +Use GET /info/variation/populations/:species?filter=LD to +retrieve a list of all populations with LD data. This endpoint is already +implemented. Please, use \code{\link[=get_species_populations]{get_species_populations()}} with filter "LD" +to retrieve valid populations.} + +\item{attribs}{\emph{(Optional)} A boolean indicating whether +to add variation attributes such as chromosome, start, end, strand, +consequence type, and clinical significance. Default is NULL.} + +\item{callback}{\emph{(Optional)} A string representing the name of the +callback subroutine for JSONP responses.} + +\item{d_prime}{\emph{(Optional)} A float value (0-1) to filter results +by D' (linkage disequilibrium measure). Only returns pairs with D' ≥ +the specified value. Default is NULL.} + +\item{r2}{\emph{(Optional)} A float value (0-1) to filter results by +r² (correlation coefficient). Only returns pairs with r² ≥ the specified +value.. Default is NULL.} + +\item{window_size}{\emph{(Optional)} An integer specifying the window size +in kb (max 500). Defaults to 500 kb.} +} +\value{ +A list of parsed JSON responses containing the LD values for +the provided variant. +} +\description{ +Computes and retrieves LD values between a given variant and all other +variants within a window of up to 500 kb in the specified population. +} +\note{ +See more about the implemented endpoint \code{\link[=get_ld_by_variant]{get_ld_by_variant()}} +on the following \href{https://rest.ensembl.org/documentation/info/ld}{GET ld/:species/:id/:population_name} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\examples{ +get_ld_by_variant("homo_sapiens", "rs56116432", "1000GENOMES:phase_3:KHV") +get_ld_by_variant("homo_sapiens", "rs56116432", "1000GENOMES:phase_3:KHV", + d_prime = 0.8, r2 = 0.85) +get_ld_by_variant("homo_sapiens", "rs56116432", "1000GENOMES:phase_3:KHV", + window_size = 250) + +} diff --git a/man/get_ld_values_by_region.Rd b/man/get_ld_values_by_region.Rd new file mode 100755 index 0000000..8b56604 --- /dev/null +++ b/man/get_ld_values_by_region.Rd @@ -0,0 +1,65 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_ld_values_by_region} +\alias{get_ld_values_by_region} +\title{Get Linkage Disequilibrium (LD) Values for a Genomic Region} +\usage{ +get_ld_values_by_region( + species, + region, + population_name, + callback = "randomlygeneratedname", + d_prime = NULL, + r2 = NULL +) +} +\arguments{ +\item{species}{A string representing the species name or alias +(e.g., "homo_sapiens").} + +\item{region}{A string defining the genomic region in the format +"chr:start..end". +The maximum region size allowed is 500 kb. If the region overlaps +the MHC region, the maximum is 10 kb.} + +\item{population_name}{A string representing the population for which +LD should be computed. +Use \code{\link[=get_species_populations]{get_species_populations()}} with filter "LD" to retrieve valid +populations.} + +\item{callback}{\emph{(Optional)} A string representing the name of the +callback subroutine for JSONP responses.} + +\item{d_prime}{\emph{(Optional)} A float value (0-1) to filter results +by D' (linkage disequilibrium measure). +Only returns pairs with D' ≥ the specified value.} + +\item{r2}{\emph{(Optional)} A float value (0-1) to filter results by r² +(correlation coefficient). +Only returns pairs with r² ≥ the specified value.} +} +\value{ +A parsed JSON response containing the LD values for all variant +pairs within the specified region. + +See more about the implemented endpoint \code{\link[=get_ld_values_by_region]{get_ld_values_by_region()}} +on the following \href{https://rest.ensembl.org/documentation/info/ld_region}{GET ld/:species/region/:region/:population_name} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Computes and retrieves LD values between all pairs of variants within +a defined genomic region. +} +\examples{ +get_ld_values_by_region(species = "homo_sapiens", + region = "6:25837556..25843455", + population_name = "1000GENOMES:phase_3:KHV") +get_ld_values_by_region(species = "homo_sapiens", + region = "6:25837556..25843455", + population_name = "1000GENOMES:phase_3:KHV", + r2 = 0.85) +get_ld_values_by_region(species = "homo_sapiens", + region = "6:25837556..25843455", + population_name = "1000GENOMES:phase_3:KHV", + d_prime = 1.0) +} diff --git a/man/get_pairwise_ld_values.Rd b/man/get_pairwise_ld_values.Rd new file mode 100755 index 0000000..cdbb3d7 --- /dev/null +++ b/man/get_pairwise_ld_values.Rd @@ -0,0 +1,61 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ensembl-endpoints.R +\name{get_pairwise_ld_values} +\alias{get_pairwise_ld_values} +\title{Get Pairwise Linkage Disequilibrium (LD) Values} +\usage{ +get_pairwise_ld_values( + species, + id1, + id2, + callback = "randomlygeneratedname", + d_prime = NULL, + r2 = NULL, + population_name = NULL +) +} +\arguments{ +\item{species}{A string representing the species name or +alias (e.g., "homo_sapiens").} + +\item{id1}{A string representing the first variant ID +(e.g., "rs6792369").} + +\item{id2}{A string representing the second variant ID +(e.g., "rs1042779").} + +\item{callback}{\emph{(Optional)} A string representing the name of +the callback +subroutine for JSONP responses.} + +\item{d_prime}{\emph{(Optional)} A float value (0-1) to filter results +by D' (linkage disequilibrium measure). +Only returns pairs with D' ≥ the specified value.} + +\item{r2}{\emph{(Optional)} A float value (0-1) to filter results by r² +(correlation coefficient). Only returns pairs with r² ≥ the specified value.} + +\item{population_name}{\emph{(Optional)} A string representing the population +for which to compute LD. Use \code{\link[=get_species_populations]{get_species_populations()}} with filter "LD" +to retrieve valid populations.} +} +\value{ +A parsed JSON response containing the LD values for the specified +variant pair. + +See more about the implemented endpoint \code{\link[=get_pairwise_ld_values]{get_pairwise_ld_values()}} +on the following \href{https://rest.ensembl.org/documentation/info/ld_pairwise}{GET ld/:species/pairwise/:id1/:id2} +from the official \href{https://rest.ensembl.org/}{Ensembl Rest API}. +} +\description{ +Computes and retrieves LD values between two given variants. +} +\examples{ +get_pairwise_ld_values(species = "homo_sapiens", id1 = "rs6792369", + id2 = "rs1042779") +get_pairwise_ld_values(species = "homo_sapiens", id1 = "rs6792369", + id2 = "rs1042779", r2 = 0.85) +get_pairwise_ld_values(species = "homo_sapiens", id1 = "rs6792369", + id2 = "rs1042779", d_prime = 1.0, + population_name = "1000GENOMES:phase_3:KHV") +} diff --git a/man/get_variation_sources.Rd b/man/get_variation_sources.Rd old mode 100644 new mode 100755 diff --git a/man/post.Rd b/man/post.Rd index d7da7b8..a8f7f91 100755 --- a/man/post.Rd +++ b/man/post.Rd @@ -26,7 +26,7 @@ Defaults to 15 per minute (15/60).} A list of responses, one for each request made. } \description{ -The \code{\link[=post]{post()}} function is a wrapper around the \code{\link[=reqs]{reqs()}} function that +The \code{\link[=post]{post()}} function is a wrapper around the \code{reqs} function that performs POST requests to the Ensembl API, handling rate limiting automatically. } diff --git a/tests/testthat/test-endpoints.R b/tests/testthat/test-endpoints.R index d3661d1..6dabbe0 100755 --- a/tests/testthat/test-endpoints.R +++ b/tests/testthat/test-endpoints.R @@ -3,6 +3,7 @@ skip_if_offline() test_that("Testing if the `Ensembl API` functions work correctly", { + # -------------------------------------------------------- # ## Comparative Genomics ==== test_that("`get_cafe_genetree_by_id` works", { @@ -66,6 +67,7 @@ test_that("Testing if the `Ensembl API` functions work correctly", { expect_error(get_homology_by_symbol("homo_sapiens"), "Both 'species' and 'symbol' parameters are required") }) + # -------------------------------------------------------- # ## Cross References ==== test_that("`get_xrefs_by_symbol` works", { @@ -89,6 +91,62 @@ test_that("Testing if the `Ensembl API` functions work correctly", { expect_error(get_xrefs_by_name("homo_sapiens"), "Both 'species' and 'name' parameters are required") }) + # -------------------------------------------------------- # + ## Information ==== + ## TO DO + + # -------------------------------------------------------- # + ## Linkage Disequilibrium ==== + + test_that("get_ld_by_variant works", { + result <- get_ld_by_variant(species = "homo_sapiens", id = "rs56116432", + population_name = "1000GENOMES:phase_3:KHV") + + expect_type(result, "list") + expect_true(!is.null(result)) + expect_true(length(result) > 0) + }) + + test_that("get_ld_by_variant handles missing parameters", { + expect_error(get_ld_by_variant(id = "rs56116432", population_name = "1000GENOMES:phase_3:KHV"), + "'species', 'id', and 'population_name' parameters are all required.") + expect_error(get_ld_by_variant(species = "homo_sapiens",population_name = "1000GENOMES:phase_3:KHV"), + "'species', 'id', and 'population_name' parameters are all required.") + }) + + test_that("get_pairwise_ld_values works", { + result <- get_pairwise_ld_values(species = "homo_sapiens", + id1 = "rs6792369",id2 = "rs1042779") + + expect_type(result, "list") + expect_true(!is.null(result)) + expect_true(length(result) > 0) + }) + + test_that("get_pairwise_ld_values handles missing parameters", { + expect_error(get_pairwise_ld_values(id1 = "rs6792369", id2 = "rs1042779"), + "'species', 'id1', and 'id2' parameters are all required.") + expect_error(get_pairwise_ld_values(species = "homo_sapiens", id1 = "rs6792369"), + "'species', 'id1', and 'id2' parameters are all required.") + }) + + test_that("get_ld_values_by_region works", { + result <- get_ld_values_by_region(species = "homo_sapiens", + region = "6:25837556..25843455", + population_name = "1000GENOMES:phase_3:KHV") + + expect_type(result, "list") + expect_true(!is.null(result)) + expect_true(length(result) > 0) + }) + + test_that("get_ld_values_by_region handles missing parameters", { + expect_error(get_ld_values_by_region(region = "6:25837556..25843455", population_name = "1000GENOMES:phase_3:KHV"), + "'species', 'region', and 'population_name' parameters are all required.") + expect_error(get_ld_values_by_region(species = "homo_sapiens", population_name = "1000GENOMES:phase_3:KHV"), + "'species', 'region', and 'population_name' parameters are all required.") + }) + ## test `get` id <- "ENSGT00390000003602" response <- get(res = "/cafe/genetree/id/{id}", id = id,