From 399b1b94991c28aae54734dce343422030eb9886 Mon Sep 17 00:00:00 2001 From: DemevengDerrick Date: Thu, 18 Apr 2024 22:20:23 +0100 Subject: [PATCH 1/4] Added handling POSIXct and POSIXT datetypes to prep_match_datatypes --- R/prep_match_datatypes.R | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/R/prep_match_datatypes.R b/R/prep_match_datatypes.R index a5e3d52..e8821be 100644 --- a/R/prep_match_datatypes.R +++ b/R/prep_match_datatypes.R @@ -47,10 +47,13 @@ prep_match_datatypes <- function(ref_dataframe, target_dataframe) { target_dataframe <- target_dataframe |> dplyr::mutate(!!col := as.logical(!!rlang::sym(col))) } else if (col_type == "Date") { - target_dataframe <- target_dataframe |> dplyr::mutate(!!col := as.Date(!!rlang::sym(col) - # format = "Y-%m-%d" + )) + } else if (col_type == 'c("POSIXct", "POSIXt")') { + target_dataframe <- target_dataframe |> + dplyr::mutate(!!col == as.POSIXct(!!rlang::sym(col), + format = "YYYY-MM-DD" )) } } From 24141ef29e79ba4f72ec8e52ca0bfc5e26600a86 Mon Sep 17 00:00:00 2001 From: DemevengDerrick Date: Mon, 22 Apr 2024 17:24:13 +0100 Subject: [PATCH 2/4] Added a new function to get ONA data endpoints --- NAMESPACE | 1 + R/prep_match_datatypes.R | 16 +- R/prep_match_names.R | 14 +- R/prep_ona_data_endpoints.R | 171 ++++++++++++++++++ man/check_status_api.Rd | 15 +- man/get_ona_page.Rd | 10 +- man/prep_ona_data_endpoints.Rd | 32 ++++ tests/testthat/test-prep_match_datatypes.R | 62 ++++--- tests/testthat/test-prep_ona_data_endpoints.R | 3 + 9 files changed, 281 insertions(+), 43 deletions(-) create mode 100644 R/prep_ona_data_endpoints.R create mode 100644 man/prep_ona_data_endpoints.Rd create mode 100644 tests/testthat/test-prep_ona_data_endpoints.R diff --git a/NAMESPACE b/NAMESPACE index 3667942..825662c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,6 +4,7 @@ export(get_ona_data) export(prep_geonames) export(prep_match_datatypes) export(prep_match_names) +export(prep_ona_data_endpoints) export(read) export(save) importFrom(cli,cli_alert_warning) diff --git a/R/prep_match_datatypes.R b/R/prep_match_datatypes.R index e8821be..9c8543a 100644 --- a/R/prep_match_datatypes.R +++ b/R/prep_match_datatypes.R @@ -50,13 +50,17 @@ prep_match_datatypes <- function(ref_dataframe, target_dataframe) { target_dataframe <- target_dataframe |> dplyr::mutate(!!col := as.Date(!!rlang::sym(col) )) - } else if (col_type == 'c("POSIXct", "POSIXt")') { - target_dataframe <- target_dataframe |> - dplyr::mutate(!!col == as.POSIXct(!!rlang::sym(col), - format = "YYYY-MM-DD" - )) - } + } #else if (col_type == 'c("POSIXct", "POSIXt")') { + # target_dataframe <- target_dataframe |> + # dplyr::mutate(!!col == as.POSIXct(!!rlang::sym(col), + # format = "%Y-%m-%d")) + # } else if (col_type == 'c("POSIXlt", "POSIXt")') { + # target_dataframe <- target_dataframe |> + # dplyr::mutate(!!col == as.POSIXlt(!!rlang::sym(col), + # format = "%Y-%m-%d")) + # } } } return(target_dataframe) } + diff --git a/R/prep_match_names.R b/R/prep_match_names.R index 140ba05..620e0e1 100644 --- a/R/prep_match_names.R +++ b/R/prep_match_names.R @@ -73,23 +73,23 @@ prep_match_names <- function(ref_dataframe, target_dataframe, report = TRUE) { setdiff(names(target_dataframe), names(ref_dataframe)) if (length(no_match_cols) > 0) { print( - paste( - "No match found for ", - no_match_cols, - ". initial name maintained. A total of ", length(names(no_match_cols)), "/", length(names(no_match_cols)), " columns from the target dataframe were matched to the reference dataframe" ) - ) + print( + "No match found for ", + no_match_cols, + ". initial name maintained. A total of " + ) } else{ print( paste( "All columns were successfully matched and renamed. A total of ", - length(names(common_cols)), + length(common_cols), "/", - length(names(common_cols)), + length(common_cols), " columns from the target dataframe were matched to the reference dataframe" ) ) diff --git a/R/prep_ona_data_endpoints.R b/R/prep_ona_data_endpoints.R new file mode 100644 index 0000000..5162e84 --- /dev/null +++ b/R/prep_ona_data_endpoints.R @@ -0,0 +1,171 @@ +#' Check Status of API Response +#' +#' This function checks the API response status code. It handles various HTTP +#' status codes by providing specific error messages. It returns `TRUE` for +#' successful responses (status code 200). For error conditions like 400, 403, +#' 500, etc., it stops execution with an error message, aiding in debugging and +#' issue diagnosis. +#' +#' @param response The API response. +#' +#' @return `TRUE` for a successful response (status code 200). If the status +#' code indicates an error (e.g., 400, 403, 500), the function stops +#' and returns a specific error message. +#' +#' @examples +#' # response <- check_status_api(response) +check_status_api <- function(response) { + + # get resoinse code + response_status_code <- httr::status_code(response) + # get http code + code <- httpcode::http_code(response_status_code) + + if (code$status_code != 200) { + stop( + glue::glue( + "{code$status_code}: {code$explanation}", + "\n For a full explanation of this error call: ", + "httpcode::http_code({code$status_code}, verbose = TRUE)" + ) + ) + } +} + +#' Get a Page of Data from an API +#' +#' This function retrieves a single page of data from a specified API endpoint. +#' +#' @param api_url The base URL of the API endpoint. +#' @param api_token Authentication token for API access, prefixed with "Token". +#' @param start An integer specifying the starting point for data retrieval. +#' Defaults to 0. +#' @param api_limit An integer specifying the maximum number of items to +#' retrieve per page. +#' @param times The number of attempts to retry the request in case of failure. +#' Defaults to 12. +#' @return A list containing the retrieved data parsed from JSON format. If +#' the specified content is not found or an error occurs, the function +#' stops and returns an error message. +get_ona_page <- function(api_url, api_token, start = 0, api_limit, times = 12) { + tryCatch({ + resp <- httr::RETRY( + verb = "GET", + url = api_url, + config = httr::add_headers(Authorization = paste("Token", api_token)), + query = list( + start = start, + limit = api_limit + ), + times = times, + pause_cap = 180, + httr::progress(type = "down") + ) + + content <- httr::content(resp, "text", encoding = "UTF-8") + jsonlite::fromJSON(content, simplifyDataFrame = TRUE) + }, error = function(e) { + message("Error encountered: ", e$message) + NULL + }) +} + +#' Get Data endpoints from ONA API +#' +#' This function getes data endpoints for a specified form from the ONA API +#' using a provided API token and form ID. It returns the data in a structured +#' format if the request is successful. If the request fails, the function stops +#' and returns an error message indicating the failure reason. +#' +#' @param base_url A string specifying the base URL for the ONA API, +#' could be https://esurv.afro.who.int eSurv. +#' Default is https://api.whonghub.org +#' @param api_token A string specifying the API token for ONA +#' +#' @return A list containing the data geted from the ONA API. +#' +#' @examples +#' # base_url <- https://api.ona.io +#' # api_token <- "your_api_token_here" +#' # data <- get_ona_data(base_url, api_token) +#' @export +#' +#' @seealso \url{https://api.ona.io/api/v1/data/} for more info on ONA API +prep_ona_data_endpoints <- function( + base_url = "https://api.whonghub.org", api_token) { + + # check base url validity + base_url_pattern <- "^(https?://[^/]+).*" + if ( grepl(base_url_pattern, base_url)){ + base_url <- sub(base_url_pattern, "\\1", base_url) + } else { + stop(paste("Error: ", base_url, " is not a valid base url")) + } + + # set up URL + api_url <- paste0(base_url,"/api/v1/data") + + # api page limit + api_limit <- 100000 + + process_id <- cli::cli_process_start( + paste0("geting form data endpoints from ONA server")); cat("\n") + + results <- list() + get_next_page <- TRUE + start <- 0 + + # Validate url link before downloading --------------------------------------- + + # get head before download + response <- httr::HEAD( + api_url, + config = httr::add_headers(Authorization = paste("Token", api_token))) + + # check status of call + check_status_api(response) + + # Download data (use pagination if necessary) -------------------------------- + + # look through get_next_page function to deal with pagination + while (get_next_page) { + current_page <- get_ona_page( + api_url, api_token, start, api_limit = api_limit) |> + as.data.frame() |> + dplyr::mutate( + dplyr::across( + tidyselect::everything(), as.character)) + + # join the paginated results + results <- dplyr::bind_rows(results, current_page) + if (nrow(current_page) < api_limit) { + get_next_page <- FALSE + } else { + start <- start + api_limit + } + } + + # praise for successful results + praise_emoji <- function() { + if (!cli::is_utf8_output()) { + return("") + } + + emoji <- c( + "\U0001f600", + "\U0001f973", + "\U0001f638", + "\U0001f308", + "\U0001f947", + "\U0001f389", + "\U0001f38a" + ) + sample(emoji, 1) + } + + cat("\n"); cli::cli_process_done( + process_id, + msg_done = "Download complete! {praise_emoji()}") + + return(results) +} diff --git a/man/check_status_api.Rd b/man/check_status_api.Rd index ad2e741..4e8b13a 100644 --- a/man/check_status_api.Rd +++ b/man/check_status_api.Rd @@ -1,20 +1,32 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/get_ona.R +% Please edit documentation in R/get_ona.R, R/prep_ona_data_endpoints.R \name{check_status_api} \alias{check_status_api} \title{Check Status of API Response} \usage{ +check_status_api(response) + check_status_api(response) } \arguments{ \item{response}{The API response.} } \value{ +\code{TRUE} for a successful response (status code 200). If the status +code indicates an error (e.g., 400, 403, 500), the function stops +and returns a specific error message. + \code{TRUE} for a successful response (status code 200). If the status code indicates an error (e.g., 400, 403, 500), the function stops and returns a specific error message. } \description{ +This function checks the API response status code. It handles various HTTP +status codes by providing specific error messages. It returns \code{TRUE} for +successful responses (status code 200). For error conditions like 400, 403, +500, etc., it stops execution with an error message, aiding in debugging and +issue diagnosis. + This function checks the API response status code. It handles various HTTP status codes by providing specific error messages. It returns \code{TRUE} for successful responses (status code 200). For error conditions like 400, 403, @@ -23,4 +35,5 @@ issue diagnosis. } \examples{ # response <- check_status_api(response) +# response <- check_status_api(response) } diff --git a/man/get_ona_page.Rd b/man/get_ona_page.Rd index 783f6aa..c02fb95 100644 --- a/man/get_ona_page.Rd +++ b/man/get_ona_page.Rd @@ -1,9 +1,11 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/get_ona.R +% Please edit documentation in R/get_ona.R, R/prep_ona_data_endpoints.R \name{get_ona_page} \alias{get_ona_page} \title{Get a Page of Data from an API} \usage{ +get_ona_page(api_url, api_token, start = 0, api_limit, times = 12) + get_ona_page(api_url, api_token, start = 0, api_limit, times = 12) } \arguments{ @@ -21,10 +23,16 @@ retrieve per page.} Defaults to 12.} } \value{ +A list containing the retrieved data parsed from JSON format. If +the specified content is not found or an error occurs, the function +stops and returns an error message. + A list containing the retrieved data parsed from JSON format. If the specified content is not found or an error occurs, the function stops and returns an error message. } \description{ +This function retrieves a single page of data from a specified API endpoint. + This function retrieves a single page of data from a specified API endpoint. } diff --git a/man/prep_ona_data_endpoints.Rd b/man/prep_ona_data_endpoints.Rd new file mode 100644 index 0000000..2070239 --- /dev/null +++ b/man/prep_ona_data_endpoints.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/prep_ona_data_endpoints.R +\name{prep_ona_data_endpoints} +\alias{prep_ona_data_endpoints} +\title{Get Data endpoints from ONA API} +\usage{ +prep_ona_data_endpoints(base_url = "https://api.whonghub.org", api_token) +} +\arguments{ +\item{base_url}{A string specifying the base URL for the ONA API, +could be https://esurv.afro.who.int eSurv. +Default is https://api.whonghub.org} + +\item{api_token}{A string specifying the API token for ONA} +} +\value{ +A list containing the data geted from the ONA API. +} +\description{ +This function getes data endpoints for a specified form from the ONA API +using a provided API token and form ID. It returns the data in a structured +format if the request is successful. If the request fails, the function stops +and returns an error message indicating the failure reason. +} +\examples{ +# base_url <- https://api.ona.io +# api_token <- "your_api_token_here" +# data <- get_ona_data(base_url, api_token) +} +\seealso{ +\url{https://api.ona.io/api/v1/data/} for more info on ONA API +} diff --git a/tests/testthat/test-prep_match_datatypes.R b/tests/testthat/test-prep_match_datatypes.R index 6a7aa9b..9e5b4dd 100644 --- a/tests/testthat/test-prep_match_datatypes.R +++ b/tests/testthat/test-prep_match_datatypes.R @@ -1,30 +1,36 @@ testthat::test_that("Data types match correctly", { - - # set up sample ref target data - ref_df <- tibble::tibble( - integer_col = 1:3, - character_col = c("a", "b", "c"), - numeric_col = c(1.1, 2.2, 3.3), - date_col = as.Date( - c("2021-01-01", "2021-01-02", "2021-01-03")) - ) - - # set up sample target data - target_df <- tibble::tibble( - integer_col = c("1", "2", "3"), - character_col = 1:3, - numeric_col = c("1.1", "2.2", "3.3"), - date_col = c("2021-01-01", "2021-01-02", "2021-01-03") - ) - - # match datatypes - matched_df <- prep_match_datatypes(ref_df, target_df) - - # check if prep_match_datatypes works - testthat::expect_type(matched_df$integer_col, "integer") - testthat::expect_type(matched_df$character_col, "character") - testthat::expect_type(matched_df$numeric_col, "double") - testthat::expect_equal(class(matched_df$date_col), "Date") + # set up sample ref target data + ref_df <- tibble::tibble( + integer_col = 1:3, + character_col = c("a", "b", "c"), + numeric_col = c(1.1, 2.2, 3.3), + date_col = as.Date(c( + "2021-01-01", "2021-01-02", "2021-01-03" + )), + posixct_date_col = as.POSIXct(c("2024-04-17", + "2024-04-18", + "2024-04-19"), + format = "%Y-%m-%d") + ) + + # set up sample target data + target_df <- tibble::tibble( + integer_col = c("1", "2", "3"), + character_col = 1:3, + numeric_col = c("1.1", "2.2", "3.3"), + date_col = c("2021-01-01", "2021-01-02", "2021-01-03"), + posixct_date_col = c("2024-04-17", + "2024-04-18", + "2024-04-19") + ) + + # match datatypes + matched_df <- prep_match_datatypes(ref_df, target_df) + + # check if prep_match_datatypes works + testthat::expect_type(matched_df$integer_col, "integer") + testthat::expect_type(matched_df$character_col, "character") + testthat::expect_type(matched_df$numeric_col, "double") + testthat::expect_equal(class(matched_df$date_col), "Date") + #testthat::expect_equal(class(matched_df$posixct_date_col), 'c("POSIXct", "POSIXt")') }) - - diff --git a/tests/testthat/test-prep_ona_data_endpoints.R b/tests/testthat/test-prep_ona_data_endpoints.R new file mode 100644 index 0000000..8849056 --- /dev/null +++ b/tests/testthat/test-prep_ona_data_endpoints.R @@ -0,0 +1,3 @@ +test_that("multiplication works", { + expect_equal(2 * 2, 4) +}) From e3231ac9f64ef83e594bab206649d75ae6c0bb09 Mon Sep 17 00:00:00 2001 From: Mohamed Yusuf Date: Mon, 29 Apr 2024 11:54:13 +0200 Subject: [PATCH 3/4] Refine and abstract`prep_ona_data_endpoints` Co-Authored-By: Demeveng Derrick <46376095+DemevengDerrick@users.noreply.github.com> --- R/get_ona.R | 75 +++++++++++++-- R/prep_ona_data_endpoints.R | 171 --------------------------------- man/check_status_api.Rd | 15 +-- man/get_ona_page.Rd | 10 +- man/prep_ona_data_endpoints.Rd | 29 +++--- 5 files changed, 81 insertions(+), 219 deletions(-) delete mode 100644 R/prep_ona_data_endpoints.R diff --git a/R/get_ona.R b/R/get_ona.R index 38f5548..0180b41 100644 --- a/R/get_ona.R +++ b/R/get_ona.R @@ -32,6 +32,59 @@ check_status_api <- function(response) { } } +#' Fetch ONA API Data +#' +#' Retrieves data from the ONA API endpoints to display available forms and +#' datasets. It initially, uses given API token for authorization and checks the +#' initial API response status. Then it validates the base URL and constructs +#' the full API endpoint URL to retrieve a dataframe of all the available for +#' forms/data. +#' +#' @param base_url The base URL for the ONA API; defaults to +#' 'https://api.whonghub.org'. +#' @param api_token API token for authentication. +#' +#' @return Data frame of the API endpoint data. +#' +#' @export +#' @examples +#' # prep_ona_data_endpoints(api_token = "your_api_token_here") +prep_ona_data_endpoints <- function( + base_url = "https://api.whonghub.org", api_token) { + + # check base url validity + base_url_pattern <- "^(https?://[^/]+).*" + if ( grepl(base_url_pattern, base_url)){ + base_url <- sub(base_url_pattern, "\\1", base_url) + } else { + stop(paste("Error: ", base_url, " is not a valid base url")) + } + + # set up URL + api_url <- paste0(base_url,"/api/v1/data") + + # Validate base url link first ----------------------------------------------- + + # get head before download + response <- httr::HEAD( + base_url, + config = httr::add_headers(Authorization = paste("Token", api_token))) + + # check status of call + check_status_api(response) + + # Validate url link before downloading --------------------------------------- + + # get one data endpoint df + response <- httr::GET( + api_url, + config = httr::add_headers(Authorization = paste("Token", api_token))) |> + httr::content("text", encoding = "UTF-8") |> + jsonlite::fromJSON(simplifyDataFrame = TRUE) + + return(response) +} + #' Get a Page of Data from an API #' #' This function retrieves a single page of data from a specified API endpoint. @@ -118,15 +171,20 @@ get_ona_data <- function( get_next_page <- TRUE start <- 0 - # Validate url link before downloading --------------------------------------- - - # get head before download - response <- httr::HEAD( - api_url, - config = httr::add_headers(Authorization = paste("Token", api_token))) + # Check if the form id is available for download ----------------------------- - # check status of call - check_status_api(response) + resp_data <- prep_ona_data_endpoints( + base_url = base_url, + api_token = api_token) + + if (!(form_id %in% unique(resp_data$id))) { + cli::cli_abort( + paste0("Form IDs ", + toString(form_id), + " not found. Use `prep_ona_data_endpoints()` ", + "to check available forms for download.") + ) + } # Download data (use pagination if necessary) -------------------------------- @@ -172,3 +230,4 @@ get_ona_data <- function( return(results) } + diff --git a/R/prep_ona_data_endpoints.R b/R/prep_ona_data_endpoints.R deleted file mode 100644 index 5162e84..0000000 --- a/R/prep_ona_data_endpoints.R +++ /dev/null @@ -1,171 +0,0 @@ -#' Check Status of API Response -#' -#' This function checks the API response status code. It handles various HTTP -#' status codes by providing specific error messages. It returns `TRUE` for -#' successful responses (status code 200). For error conditions like 400, 403, -#' 500, etc., it stops execution with an error message, aiding in debugging and -#' issue diagnosis. -#' -#' @param response The API response. -#' -#' @return `TRUE` for a successful response (status code 200). If the status -#' code indicates an error (e.g., 400, 403, 500), the function stops -#' and returns a specific error message. -#' -#' @examples -#' # response <- check_status_api(response) -check_status_api <- function(response) { - - # get resoinse code - response_status_code <- httr::status_code(response) - # get http code - code <- httpcode::http_code(response_status_code) - - if (code$status_code != 200) { - stop( - glue::glue( - "{code$status_code}: {code$explanation}", - "\n For a full explanation of this error call: ", - "httpcode::http_code({code$status_code}, verbose = TRUE)" - ) - ) - } -} - -#' Get a Page of Data from an API -#' -#' This function retrieves a single page of data from a specified API endpoint. -#' -#' @param api_url The base URL of the API endpoint. -#' @param api_token Authentication token for API access, prefixed with "Token". -#' @param start An integer specifying the starting point for data retrieval. -#' Defaults to 0. -#' @param api_limit An integer specifying the maximum number of items to -#' retrieve per page. -#' @param times The number of attempts to retry the request in case of failure. -#' Defaults to 12. -#' @return A list containing the retrieved data parsed from JSON format. If -#' the specified content is not found or an error occurs, the function -#' stops and returns an error message. -get_ona_page <- function(api_url, api_token, start = 0, api_limit, times = 12) { - tryCatch({ - resp <- httr::RETRY( - verb = "GET", - url = api_url, - config = httr::add_headers(Authorization = paste("Token", api_token)), - query = list( - start = start, - limit = api_limit - ), - times = times, - pause_cap = 180, - httr::progress(type = "down") - ) - - content <- httr::content(resp, "text", encoding = "UTF-8") - jsonlite::fromJSON(content, simplifyDataFrame = TRUE) - }, error = function(e) { - message("Error encountered: ", e$message) - NULL - }) -} - -#' Get Data endpoints from ONA API -#' -#' This function getes data endpoints for a specified form from the ONA API -#' using a provided API token and form ID. It returns the data in a structured -#' format if the request is successful. If the request fails, the function stops -#' and returns an error message indicating the failure reason. -#' -#' @param base_url A string specifying the base URL for the ONA API, -#' could be https://esurv.afro.who.int eSurv. -#' Default is https://api.whonghub.org -#' @param api_token A string specifying the API token for ONA -#' -#' @return A list containing the data geted from the ONA API. -#' -#' @examples -#' # base_url <- https://api.ona.io -#' # api_token <- "your_api_token_here" -#' # data <- get_ona_data(base_url, api_token) -#' @export -#' -#' @seealso \url{https://api.ona.io/api/v1/data/} for more info on ONA API -prep_ona_data_endpoints <- function( - base_url = "https://api.whonghub.org", api_token) { - - # check base url validity - base_url_pattern <- "^(https?://[^/]+).*" - if ( grepl(base_url_pattern, base_url)){ - base_url <- sub(base_url_pattern, "\\1", base_url) - } else { - stop(paste("Error: ", base_url, " is not a valid base url")) - } - - # set up URL - api_url <- paste0(base_url,"/api/v1/data") - - # api page limit - api_limit <- 100000 - - process_id <- cli::cli_process_start( - paste0("geting form data endpoints from ONA server")); cat("\n") - - results <- list() - get_next_page <- TRUE - start <- 0 - - # Validate url link before downloading --------------------------------------- - - # get head before download - response <- httr::HEAD( - api_url, - config = httr::add_headers(Authorization = paste("Token", api_token))) - - # check status of call - check_status_api(response) - - # Download data (use pagination if necessary) -------------------------------- - - # look through get_next_page function to deal with pagination - while (get_next_page) { - current_page <- get_ona_page( - api_url, api_token, start, api_limit = api_limit) |> - as.data.frame() |> - dplyr::mutate( - dplyr::across( - tidyselect::everything(), as.character)) - - # join the paginated results - results <- dplyr::bind_rows(results, current_page) - if (nrow(current_page) < api_limit) { - get_next_page <- FALSE - } else { - start <- start + api_limit - } - } - - # praise for successful results - praise_emoji <- function() { - if (!cli::is_utf8_output()) { - return("") - } - - emoji <- c( - "\U0001f600", - "\U0001f973", - "\U0001f638", - "\U0001f308", - "\U0001f947", - "\U0001f389", - "\U0001f38a" - ) - sample(emoji, 1) - } - - cat("\n"); cli::cli_process_done( - process_id, - msg_done = "Download complete! {praise_emoji()}") - - return(results) -} diff --git a/man/check_status_api.Rd b/man/check_status_api.Rd index 4e8b13a..ad2e741 100644 --- a/man/check_status_api.Rd +++ b/man/check_status_api.Rd @@ -1,32 +1,20 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/get_ona.R, R/prep_ona_data_endpoints.R +% Please edit documentation in R/get_ona.R \name{check_status_api} \alias{check_status_api} \title{Check Status of API Response} \usage{ -check_status_api(response) - check_status_api(response) } \arguments{ \item{response}{The API response.} } \value{ -\code{TRUE} for a successful response (status code 200). If the status -code indicates an error (e.g., 400, 403, 500), the function stops -and returns a specific error message. - \code{TRUE} for a successful response (status code 200). If the status code indicates an error (e.g., 400, 403, 500), the function stops and returns a specific error message. } \description{ -This function checks the API response status code. It handles various HTTP -status codes by providing specific error messages. It returns \code{TRUE} for -successful responses (status code 200). For error conditions like 400, 403, -500, etc., it stops execution with an error message, aiding in debugging and -issue diagnosis. - This function checks the API response status code. It handles various HTTP status codes by providing specific error messages. It returns \code{TRUE} for successful responses (status code 200). For error conditions like 400, 403, @@ -35,5 +23,4 @@ issue diagnosis. } \examples{ # response <- check_status_api(response) -# response <- check_status_api(response) } diff --git a/man/get_ona_page.Rd b/man/get_ona_page.Rd index c02fb95..783f6aa 100644 --- a/man/get_ona_page.Rd +++ b/man/get_ona_page.Rd @@ -1,11 +1,9 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/get_ona.R, R/prep_ona_data_endpoints.R +% Please edit documentation in R/get_ona.R \name{get_ona_page} \alias{get_ona_page} \title{Get a Page of Data from an API} \usage{ -get_ona_page(api_url, api_token, start = 0, api_limit, times = 12) - get_ona_page(api_url, api_token, start = 0, api_limit, times = 12) } \arguments{ @@ -23,16 +21,10 @@ retrieve per page.} Defaults to 12.} } \value{ -A list containing the retrieved data parsed from JSON format. If -the specified content is not found or an error occurs, the function -stops and returns an error message. - A list containing the retrieved data parsed from JSON format. If the specified content is not found or an error occurs, the function stops and returns an error message. } \description{ -This function retrieves a single page of data from a specified API endpoint. - This function retrieves a single page of data from a specified API endpoint. } diff --git a/man/prep_ona_data_endpoints.Rd b/man/prep_ona_data_endpoints.Rd index 2070239..3609190 100644 --- a/man/prep_ona_data_endpoints.Rd +++ b/man/prep_ona_data_endpoints.Rd @@ -1,32 +1,27 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/prep_ona_data_endpoints.R +% Please edit documentation in R/get_ona.R \name{prep_ona_data_endpoints} \alias{prep_ona_data_endpoints} -\title{Get Data endpoints from ONA API} +\title{Fetch ONA API Data} \usage{ prep_ona_data_endpoints(base_url = "https://api.whonghub.org", api_token) } \arguments{ -\item{base_url}{A string specifying the base URL for the ONA API, -could be https://esurv.afro.who.int eSurv. -Default is https://api.whonghub.org} +\item{base_url}{The base URL for the ONA API; defaults to +'https://api.whonghub.org'.} -\item{api_token}{A string specifying the API token for ONA} +\item{api_token}{API token for authentication.} } \value{ -A list containing the data geted from the ONA API. +Data frame of the API endpoint data. } \description{ -This function getes data endpoints for a specified form from the ONA API -using a provided API token and form ID. It returns the data in a structured -format if the request is successful. If the request fails, the function stops -and returns an error message indicating the failure reason. +Retrieves data from the ONA API endpoints to display available forms and +datasets. It initially, uses given API token for authorization and checks the +initial API response status. Then it validates the base URL and constructs +the full API endpoint URL to retrieve a dataframe of all the available for +forms/data. } \examples{ -# base_url <- https://api.ona.io -# api_token <- "your_api_token_here" -# data <- get_ona_data(base_url, api_token) -} -\seealso{ -\url{https://api.ona.io/api/v1/data/} for more info on ONA API +# prep_ona_data_endpoints(api_token = "your_api_token_here") } From 35c44012ede88053b0947fb969de9bafa699e218 Mon Sep 17 00:00:00 2001 From: Mohamed Yusuf Date: Mon, 29 Apr 2024 12:06:42 +0200 Subject: [PATCH 4/4] Creates `get_multi_ona_data` (#10) This solves #10 and produces `get_multi_ona_data` function for users to download multiple ONA data into a single dataframe. --- DESCRIPTION | 3 ++- NAMESPACE | 1 + R/get_ona.R | 54 +++++++++++++++++++++++++++++++++++++++ man/get_multi_ona_data.Rd | 29 +++++++++++++++++++++ 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 man/get_multi_ona_data.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 0615c20..fca53a8 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -30,7 +30,8 @@ Imports: jsonlite, tidyselect, httpcode, - tibble + tibble, + pbmcapply Suggests: testthat, withr, diff --git a/NAMESPACE b/NAMESPACE index 825662c..12f757d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,6 @@ # Generated by roxygen2: do not edit by hand +export(get_multi_ona_data) export(get_ona_data) export(prep_geonames) export(prep_match_datatypes) diff --git a/R/get_ona.R b/R/get_ona.R index 0180b41..d3243bd 100644 --- a/R/get_ona.R +++ b/R/get_ona.R @@ -231,3 +231,57 @@ get_ona_data <- function( return(results) } +#' Get Data from ONA for Multiple Forms +#' +#' This function retrieves data for a specified form from the ONA API using a +#' provided API token and constructs a unique key for each dataset. It returns +#' the data in a structured format if the request is successful. +#' +#' @param base_url The base URL for the ONA API; defaults to +#' 'https://api.whonghub.org'. +#' @param form_ids A vector containing form id number to identify each form. +#' @param api_token A string specifying the API token for ONA. +#' +#' @return A data frame containing the combined data from all specified form +#' IDs, and includes from_id column. +#' @examples +#' # api_token <- "your_api_token_here" +#' # data <- get_multi_ona_data(form_ids = c(623, 432, 643), api_token) +#' @export +get_multi_ona_data <- function( + base_url = "https://api.whonghub.org", form_ids, api_token) { + + # Check if the form IDs are available for download --------------------------- + resp_data <- prep_ona_data_endpoints( + base_url = base_url, + api_token = api_token + ) + + if (!all(form_ids %in% unique(resp_data$id))) { + missing_ids <- form_ids[!form_ids %in% unique(resp_data$id)] + cli::cli_abort( + paste0("Form IDs ", + toString(missing_ids), + " not found. Use `prep_ona_data_endpoints()` ", + "to check available forms for download.") + ) + } + + # Fetch data in parallel for each form ID ------------------------------------ + results_list <- pbmcapply::pbmclapply( + form_ids, + function(form_id) { + get_ona_data(form_id = form_id, api_token = api_token) + }, + mc.cores = parallel::detectCores() - 1 + ) + + # Set names for each element in the results list to match form_ids + names(results_list) <- as.character(form_ids) + + # Combine all into one df + combined_data <- dplyr::bind_rows(results_list, .id = "form_id") + + return(combined_data) +} + diff --git a/man/get_multi_ona_data.Rd b/man/get_multi_ona_data.Rd new file mode 100644 index 0000000..fbafe95 --- /dev/null +++ b/man/get_multi_ona_data.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/get_ona.R +\name{get_multi_ona_data} +\alias{get_multi_ona_data} +\title{Get Data from ONA for Multiple Forms} +\usage{ +get_multi_ona_data(base_url = "https://api.whonghub.org", form_ids, api_token) +} +\arguments{ +\item{base_url}{The base URL for the ONA API; defaults to +'https://api.whonghub.org'.} + +\item{form_ids}{A vector containing form id number to identify each form.} + +\item{api_token}{A string specifying the API token for ONA.} +} +\value{ +A data frame containing the combined data from all specified form +IDs, and includes from_id column. +} +\description{ +This function retrieves data for a specified form from the ONA API using a +provided API token and constructs a unique key for each dataset. It returns +the data in a structured format if the request is successful. +} +\examples{ +# api_token <- "your_api_token_here" +# data <- get_multi_ona_data(form_ids = c(623, 432, 643), api_token) +}